1 In this vignette

In this cell annotation vignette, we will be taking the output from the Data Integration vignette and identifying cell types and subtypes by expression of key marker genes. Herein, we will do the following:

  1. Perform low-resolution clustering
  2. Identify cell types using differentially expressed genes.
  3. Recluster each cell type at higher resolution.
  4. Identify cell subtypes within broad cell type clusters using differentially expressed genes.
  5. Run SingleR to help confirm annotations.

2 Prepare the R environment

2.1 Load in the necessary libraries

2.2 Load in our Seurat object

This .rds file comes from Vignette #2 - Data Integration.

3 Clustering and visualization

Seurat uses K-nearest neighbor clustering based on PCA and then clusters the cells using the Louvain algorithm. Nearest neighbor clustering requires input of dimensions. Based on the JackStrawPlot and ElbowPlot, we will use all 50 PCs and could likely use even more. However, it is noted that there are diminishing returns on the number of PCs, so 50 will be sufficient.

3.1 Clustree

Resolution of the Louvain clustering algorithm greatly affects number of identified clusters. This can be visualized by iterating over multiple resolutions and then plotting using Clustree. The resulting clustering is stored in the metaData of our integrated Seurat object.

4 SingleR

The R package SingleR uses microarray reference datasets to attempt to annotate each individual cell. We will use this package as a tool to support cluster identification. https://bioconductor.org/packages/release/bioc/html/SingleR.html References for SingleR are provided by the pokedex for cells celldex. In this case, we will run SinglerR with two different databases: 1) Immgen and 2) MouseRNAseq from the gene expression omnibus.

5 Low-level Cluster Identification

Seurat has a built in function for differential expression across identities. In this case, our identities are currently numbered clusters and setting FindAllMarkers to report only genes expression in at least 50% of cells (for a given cluster) and with a positive fold change will give us markers that are highly expressed within each cluster. The max.cells.per.ident option limits the amount of cells included to reduce computational time.

lowlevel.markers <- FindAllMarkers(data.integrated, only.pos = TRUE, min.pct = 0.50, logfc.threshold = 0.25, max.cells.per.ident=1000, verbose=FALSE)
#Store the top10 markers for each cluster and write it to a table
top10 <- lowlevel.markers %>% group_by(cluster) %>% top_n(n = 10, wt = avg_log2FC)
Registered S3 method overwritten by 'cli':
  method     from         
  print.boxx spatstat.geom
#Put the top10 markers for each cluster into a formatted table
top10 %>% formattable()

5.1 Rename low-level identities

Using the annotations from SingleR and the differentially expressed genes, we can assign annotations to each cell type cluster. For this, we heavily reference literature and seek to identify known cell type marker genes. We will further refine and adjust these results when we have more granular cell type annotations after subclustering.

#Rename clusters based on their deduced identities
data.integrated <- RenameIdents(data.integrated,
                                '0' = "Macrophages",
                                '1' = "Macrophages",
                                '2' = "Monocytes",
                                '3' = "B Cells",
                                '4' = "Macrophages",
                                '5' = "Dendritic Cells",
                                '6' = "Dendritic Cells",
                                '7' = "T Cells",
                                '8' = "NK Cells",
                                '9' = "Stromal Cells",
                                '10' = "T Cells",
                                '11' = "T Cells",
                                '12' = "Macrophages",
                                '13' = "T Cells",
                                '14' = "ILCs",
                                '15' = "Dendritic Cells",
                                '16' = "Monocytes",
                                '17' = "Plasma Cells",
                                '18' = "T Cells",
                                '19' = "Mast Cells",
                                '20' = "Dendritic Cells",
                                '21' = "Plasma Cells",
                                '22' = "Stromal Cells",
                                '23' = "Neutrophils",
                                '24' = "B Cells",
                                '25' = "Endothelial Cells",
                                '26' = "Macrophages",
                                '27' = "Dendritic Cells")

6 Plot lowlevel clusters

#Save and plot the low level identification
data.integrated$lowlevel <- Idents(data.integrated)
DimPlot(data.integrated, label=T) + NoLegend()

7 High-level Cluster Identification

For each of the 12 cell type clusters, we will subset the cells and repeat clustering to define subclusters. In this vignette, we refer to these subclusters as high-resolution or high-level clusters.

7.1 T and NK Cells

7.1.1 PCA and clustering

Run PCA and determine dimensions for clustering.

NKT <- subset(data.integrated, idents = c("T Cells", "NK Cells"))
NKT <- RunPCA(NKT, features=VariableFeatures(NKT),dims=1:30, verbose=FALSE)
ElbowPlot(NKT, ndims=30, reduction="pca")

Generate a clustering tree and determine clustering resolution for subclusters.

NKT <- FindNeighbors(NKT, dims=1:15, verbose=FALSE) 
NKT <- FindClusters(NKT, resolution=res, verbose=FALSE) 

# Clustering Tree
clustree(NKT, prefix="integrated_snn_res.") 


# Choose resolution
NKT <- FindClusters(NKT, resolution=0.3, verbose=FALSE) 

7.1.2 Dimensional Reduction

Plot the dimensional reduction for the new cell subclusters.

# Run UMAP
NKT <- RunUMAP(NKT, dims=1:15, verbose=FALSE) 

# Plot UMAP
DimPlot(NKT, reduction="umap", label=TRUE) + NoLegend() 

7.1.3 Find Subcluster Markers

Find differentially expressed markers between the subclusters.

# Find Markers
NKT.markers <- FindAllMarkers(NKT, only.pos = TRUE, min.pct = 0.50, logfc.threshold = 0.25, max.cells.per.ident=500, verbose=FALSE) 
NKT.markers.top10 %>% formattable()


# List top 10 genes for each subcluster in a table
NKT.markers.top10 <- NKT.markers %>% group_by(cluster) %>% top_n(n = 10, wt = avg_log2FC)
NKT.markers.top10 %>% formattable()

7.1.4 Rename subcluster identities

Using the information from SingleR and differential expression, assign annotations to the subclusters.

NKT <- RenameIdents(NKT,
                               '0' = "NK Cells",
                               '1' = "Effector CD8+ T Cells",
                               '2' = "Th1 CD4+ T Cells",
                               '3' = "NKT Cells",
                               '4' = "gd T cells",
                               '5' = "Memory CD8+ T Cells",
                               '6' = "Tregs",
                               '7' = "Proliferating CD8+ T Cells",
                               '8' = "Th2 CD4+ T Cells")
NKT$highlevel <- Idents(NKT)

7.1.5 Final Dim Plot

As a final check, take a look at the Dim Plot for the subclusters and confirm that it makes sense.

DimPlot(NKT, reduction="umap", group.by="highlevel", label=TRUE, repel=TRUE) + NoLegend() + labs(title="NK and T Cells")

7.2 Dendritic Cells

7.2.1 PCA and clustering

Run PCA and determine dimensions for clustering.

DCs <- subset(data.integrated, idents = c("Dendritic Cells"))
DCs <- RunPCA(DCs, features=VariableFeatures(DCs),dims=1:30, verbose=FALSE)
ElbowPlot(DCs, ndims=30, reduction="pca")

Generate a clustering tree and determine clustering resolution for subclusters.

DCs <- FindNeighbors(DCs, dims=1:15, verbose=FALSE) 
DCs <- FindClusters(DCs, resolution=res, verbose=FALSE) 

# Clustering Tree
clustree(DCs, prefix="integrated_snn_res.") 


# Choose resolution
DCs <- FindClusters(DCs, resolution=0.3, verbose=FALSE) 

7.2.2 Dimensional Reduction

Plot the dimensional reduction for the new cell subclusters.

# Run UMAP
DCs <- RunUMAP(DCs, dims=1:15, verbose=FALSE) 

# Plot UMAP
DimPlot(DCs, reduction="umap", label=TRUE) + NoLegend() 

7.2.3 Find Subcluster Markers

Find differentially expressed markers between the subclusters.

# Find Markers
DCs.markers <- FindAllMarkers(DCs, only.pos = TRUE, min.pct = 0.50, logfc.threshold = 0.25, max.cells.per.ident=500, verbose=FALSE) 
# List top 10 genes for each subcluster in a table
DCs.markers.top10 <- DCs.markers %>% group_by(cluster) %>% top_n(n = 10, wt = avg_log2FC)
DCs.markers.top10 %>% formattable()

7.2.4 Rename subcluster identities

Using the information from SingleR and differential expression, assign annotations to the subclusters.

DCs <- RenameIdents(DCs,
                               '0' = "cDC1",
                               '1' = "cDC2",
                               '2' = "moDCs",
                               '3' = "Activated cDC2",
                               '4' = "cDC1",
                               '5' = "Proliferating cDC1",
                               '6' = "cDC2",
                               '7' = "Proliferating cDC2",
                               '8' = "Proliferating cDC1",
                               '9' = "Activated cDC1",
                               '10' = "pDCs")
DCs$highlevel <- Idents(DCs)

7.2.5 Final Dim Plot

As a final check, take a look at the Dim Plot for the subclusters and confirm that it makes sense.

DimPlot(DCs, reduction="umap", group.by="highlevel", label=TRUE, repel=TRUE) + NoLegend() + labs(title="Dendritic Cells")

7.3 B and Plasma Cells

7.3.1 PCA and clustering

Run PCA and determine dimensions for clustering.

Bcells <- subset(data.integrated, idents = c("B Cells","Plasma Cells"))
Bcells <- RunPCA(Bcells, features=VariableFeatures(Bcells),dims=1:30, verbose=FALSE)
ElbowPlot(Bcells, ndims=30, reduction="pca")

Generate a clustering tree and determine clustering resolution for subclusters.

Bcells <- FindNeighbors(Bcells, dims=1:10, verbose=FALSE) 
Bcells <- FindClusters(Bcells, resolution=res, verbose=FALSE) 

# Clustering Tree
clustree(Bcells, prefix="integrated_snn_res.") 


# Choose resolution
Bcells <- FindClusters(Bcells, resolution=0.2, verbose=FALSE) 

7.3.2 Dimensional Reduction

Plot the dimensional reduction for the new cell subclusters.

# Run UMAP
Bcells <- RunUMAP(Bcells, dims=1:10, verbose=FALSE) 

# Plot UMAP
DimPlot(Bcells, reduction="umap", label=TRUE) + NoLegend() 

7.3.3 Find Subcluster Markers

Find differentially expressed markers between the subclusters.

# Find Markers
Bcells.markers <- FindAllMarkers(Bcells, only.pos = TRUE, min.pct = 0.50, logfc.threshold = 0.25, max.cells.per.ident=500, verbose=FALSE) 
# List top 10 genes for each subcluster in a table
Bcells.markers.top10 <- Bcells.markers %>% group_by(cluster) %>% top_n(n = 10, wt = avg_log2FC)
Bcells.markers.top10 %>% formattable()

7.3.4 Rename subcluster identities

Using the information from SingleR and differential expression, assign annotations to the subclusters.

Bcells <- RenameIdents(Bcells,
                               '0' = "Naive B Cells",
                               '1' = "Memory B Cells",
                               '2' = "Plasma Cells",
                               '3' = "B-1a Cells",
                               '4' = "Plasma Cells",
                               '5' = "Plasma Cells",
                               '6' = "Plasma Cells")
Bcells$highlevel <- Idents(Bcells)

7.3.5 Final Dim Plot

As a final check, take a look at the Dim Plot for the subclusters and confirm that it makes sense.

DimPlot(Bcells, reduction="umap", group.by="highlevel", label=TRUE, repel=TRUE) + NoLegend() + labs(title="B and Plasma Cells")

7.4 ILCs

7.4.1 PCA and clustering

Run PCA and determine dimensions for clustering.

ILCs <- subset(data.integrated, idents = c("ILCs"))
ILCs <- RunPCA(ILCs, features=VariableFeatures(ILCs),dims=1:30, verbose=FALSE)
ElbowPlot(ILCs, ndims=30, reduction="pca")

Generate a clustering tree and determine clustering resolution for subclusters.

7.4.2 Dimensional Reduction

Plot the dimensional reduction for the new cell subclusters.

# Run UMAP
ILCs <- RunUMAP(ILCs, dims=1:10, verbose=FALSE) 

# Plot UMAP
DimPlot(ILCs, reduction="umap", label=TRUE) + NoLegend() 

7.4.3 Find Subcluster Markers

Find differentially expressed markers between the subclusters.

# Find Markers
ILCs.markers <- FindAllMarkers(ILCs, only.pos = TRUE, min.pct = 0.50, logfc.threshold = 0.25, max.cells.per.ident=500, verbose=FALSE) 
# List top 10 genes for each subcluster in a table
ILCs.markers.top10 <- ILCs.markers %>% group_by(cluster) %>% top_n(n = 10, wt = avg_log2FC)
ILCs.markers.top10 %>% formattable()

7.4.4 Rename subcluster identities

Using the information from SingleR and differential expression, assign annotations to the subclusters.

There are not many significant differences between the two ILC clusters. Instead, we define these cells based on expression of their transcription factor expression for Gata3 and Klrg1.

RidgePlot(ILCs, features=c("Gata3","Eomes","Rorc"), assay="RNA")

ILCs <- RenameIdents(ILCs,
                               '0' = "ILC2s",
                               '1' = "ILC2s")
ILCs$highlevel <- Idents(ILCs)

7.4.5 Final Dim Plot

As a final check, take a look at the Dim Plot for the subclusters and confirm that it makes sense.

DimPlot(ILCs, reduction="umap", group.by="highlevel", label=TRUE) + NoLegend() + labs(title="Type 2 Innate Lymphocytes")

7.5 Macrophages and Monocytes

7.5.1 PCA and clustering

Run PCA and determine dimensions for clustering.

MM <- subset(data.integrated, idents = c("Macrophages","Monocytes"))
MM <- RunPCA(MM, features=VariableFeatures(MM),dims=1:30, verbose=FALSE)
ElbowPlot(MM, ndims=30, reduction="pca")

Generate a clustering tree and determine clustering resolution for subclusters.

7.5.2 Dimensional Reduction

Plot the dimensional reduction for the new cell subclusters.

# Run UMAP
MM <- RunUMAP(MM, dims=1:25, verbose=FALSE) 

# Plot UMAP
DimPlot(MM, reduction="umap", label=TRUE) + NoLegend() 

7.5.3 Find Subcluster Markers

Find differentially expressed markers between the subclusters.

# Find Markers
MM.markers <- FindAllMarkers(MM, only.pos = TRUE, min.pct = 0.50, logfc.threshold = 0.25, max.cells.per.ident=500, verbose=FALSE) 

# List top 10 genes for each subcluster in a table
MM.markers.top10 <- MM.markers %>% group_by(cluster) %>% top_n(n = 10, wt = avg_log2FC)
MM.markers.top10 %>% formattable()

7.5.4 Rename subcluster identities

Using the information from SingleR and differential expression, assign annotations to the subclusters.

Macrophages were by far the largest population and some other cell types seem to have snuck in by Louvain clustering. The high levels of local lipid may induce transcriptional profiles that cause different cell types to converge. For example, population 6 are Mast Cells unique to WC expressing high levels of Mcpt4 and Cma1, but they can be found near the lipid-associated population.

MM <- RenameIdents(MM,
                               '0' = "Tissue Resident Macrophages",
                               '1' = "Tissue Resident Macrophages",
                               '2' = "Classical Monocytes",
                               '3' = "LAMs",
                               '4' = "LAMs",
                               '5' = "Non-classical Monocytes",
                               '6' = "Proliferating Macrophages",
                               '7' = "Mast Cells",
                               '8' = "LAMs",
                               '9' = "Apoptotic Cell Clearance Macrophages")
MM$highlevel <- Idents(MM)

7.5.5 Final Dim Plot

As a final check, take a look at the Dim Plot for the subclusters and confirm that it makes sense.

DimPlot(MM, reduction="umap", group.by="highlevel", label=TRUE, repel=TRUE) + NoLegend() + labs(title="Monocytes and Macrophages")

7.6 Stromal Cells

7.6.1 PCA and clustering

Run PCA and determine dimensions for clustering.

Stromal <- subset(data.integrated, idents = c("Stromal Cells"))
Stromal <- RunPCA(Stromal, features=VariableFeatures(Stromal),dims=1:30, verbose=FALSE)
ElbowPlot(Stromal, ndims=30, reduction="pca")

Generate a clustering tree and determine clustering resolution for subclusters.

Stromal <- FindNeighbors(Stromal, dims=1:10, verbose=FALSE) 
Stromal <- FindClusters(Stromal, resolution=res, verbose=FALSE) 

# Clustering Tree
clustree(Stromal, prefix="integrated_snn_res.") 


# Choose resolution
Stromal <- FindClusters(Stromal, resolution=0.2, verbose=FALSE) 

7.6.2 Dimensional Reduction

Plot the dimensional reduction for the new cell subclusters.

# Run UMAP
Stromal <- RunUMAP(Stromal, dims=1:10, verbose=FALSE) 

# Plot UMAP
DimPlot(Stromal, reduction="umap", label=TRUE) + NoLegend() 

7.6.3 Find Subcluster Markers

Find differentially expressed markers between the subclusters.

# Find Markers
Stromal.markers <- FindAllMarkers(Stromal, only.pos = TRUE, min.pct = 0.50, logfc.threshold = 0.25, max.cells.per.ident=500, verbose=FALSE) 
# List top 10 genes for each subcluster in a table
Stromal.markers.top10 <- Stromal.markers %>% group_by(cluster) %>% top_n(n = 10, wt = avg_log2FC)
Stromal.markers.top10 %>% formattable()

7.6.4 Rename subcluster identities

Using the information from SingleR and differential expression, assign annotations to the subclusters.

Stromal <- RenameIdents(Stromal,
                               '0' = "Adipocyte Precursor Cells",
                               '1' = "Adipocyte Precursor Cells",
                               '2' = "Adipocyte Precursor Cells",
                               '3' = "Adipocyte Precursor Cells",
                               '4' = "Adipocyte Precursor Cells",
                               '5' = "Mesothelial-like Cells")
Stromal$highlevel <- Idents(Stromal)

7.6.5 Final Dim Plot

As a final check, take a look at the Dim Plot for the subclusters and confirm that it makes sense.

DimPlot(Stromal, reduction="umap", group.by="highlevel", label=TRUE, repel=TRUE) + NoLegend() + labs(title="Stromal Cells")

7.7 Mast Cells

7.7.1 PCA and clustering

Run PCA and determine dimensions for clustering.

Mast <- subset(data.integrated, idents = c("Mast Cells"))
Mast <- RunPCA(Mast, features=VariableFeatures(Mast),dims=1:30, verbose=FALSE)
ElbowPlot(Mast, ndims=30, reduction="pca")

Generate a clustering tree and determine clustering resolution for subclusters.

Mast <- FindNeighbors(Mast, dims=1:10, verbose=FALSE) 
Mast <- FindClusters(Mast, resolution=res, verbose=FALSE) 

# Clustering Tree
clustree(Mast, prefix="integrated_snn_res.") 


# Choose resolution
Mast <- FindClusters(Mast, resolution=0.2, verbose=FALSE) 

7.7.2 Dimensional Reduction

Plot the dimensional reduction for the new cell subclusters.

# Run UMAP
Mast <- RunUMAP(Mast, dims=1:10, verbose=FALSE) 

# Plot UMAP
DimPlot(Mast, reduction="umap", label=TRUE) + NoLegend() 

7.7.3 Rename subcluster identities

Using the information from SingleR and differential expression, assign annotations to the subclusters.

Mast <- RenameIdents(Mast, 
                     '0' = "Mast Cells",
                     '1' = "Mast Cells")
Mast$highlevel <- Idents(Mast)

7.7.4 Final Dim Plot

As a final check, take a look at the Dim Plot for the subclusters and confirm that it makes sense.

DimPlot(Mast, reduction="umap", group.by="highlevel", label=TRUE, repel=TRUE) + NoLegend() + labs(title="Mast Cells")

7.8 Neutrophils

7.8.1 PCA and clustering

Run PCA and determine dimensions for clustering.

Neutrophils <- subset(data.integrated, idents = c("Neutrophils"))
Neutrophils <- RunPCA(Neutrophils, features=VariableFeatures(Neutrophils),dims=1:30, verbose=FALSE)
ElbowPlot(Neutrophils, ndims=30, reduction="pca")

Generate a clustering tree and determine clustering resolution for subclusters.

Neutrophils <- FindNeighbors(Neutrophils, dims=1:10, verbose=FALSE) 
Neutrophils <- FindClusters(Neutrophils, resolution=res, verbose=FALSE) 

# Clustering Tree
clustree(Neutrophils, prefix="integrated_snn_res.") 


# Choose resolution
Neutrophils <- FindClusters(Neutrophils, resolution=0.2, verbose=FALSE) 

7.8.2 Dimensional Reduction

Plot the dimensional reduction for the new cell subclusters.

# Run UMAP
Neutrophils <- RunUMAP(Neutrophils, dims=1:10, verbose=FALSE) 

# Plot UMAP
DimPlot(Neutrophils, reduction="umap", label=TRUE) + NoLegend() 

7.8.3 Rename subcluster identities

Using the information from SingleR and differential expression, assign annotations to the subclusters.

Neutrophils <- RenameIdents(Neutrophils, '0' = "Neutrophils")
Neutrophils$highlevel <- Idents(Neutrophils)

7.8.4 Final Dim Plot

As a final check, take a look at the Dim Plot for the subclusters and confirm that it makes sense.

DimPlot(Neutrophils, reduction="umap", group.by="highlevel", label=TRUE, repel=TRUE) + NoLegend() + labs(title="Neutrophils")

7.9 Endothelial Cells

7.9.1 PCA and clustering

Run PCA and determine dimensions for clustering.

ECs <- subset(data.integrated, idents = c("Endothelial Cells"))
ECs <- RunPCA(ECs, features=VariableFeatures(ECs),dims=1:30, verbose=FALSE)
ElbowPlot(ECs, ndims=30, reduction="pca")

Generate a clustering tree and determine clustering resolution for subclusters.

ECs <- FindNeighbors(ECs, dims=1:10, verbose=FALSE) 
ECs <- FindClusters(ECs, resolution=res, verbose=FALSE) 

# Clustering Tree
clustree(ECs, prefix="integrated_snn_res.") 


# Choose resolution
ECs <- FindClusters(ECs, resolution=0.3, verbose=FALSE) 

7.9.2 Dimensional Reduction

Plot the dimensional reduction for the new cell subclusters.

# Run UMAP
ECs <- RunUMAP(ECs, dims=1:10, verbose=FALSE) 

# Plot UMAP
DimPlot(ECs, reduction="umap", label=TRUE) + NoLegend() 

7.9.3 Rename subcluster identities

Using the information from SingleR and differential expression, assign annotations to the subclusters.

ECs <- RenameIdents(ECs, '0' = "Endothelial Cells")
ECs$highlevel <- Idents(ECs)

7.9.4 Final Dim Plot

As a final check, take a look at the Dim Plot for the subclusters and confirm that it makes sense.

DimPlot(ECs, reduction="umap", group.by="highlevel", label=TRUE, repel=TRUE) + NoLegend() + labs(title="Endothelial Cells")

7.10 Store the subcluster identities

Once we have renamed our cell subclusters, we have to merge the subsetted data and then add this information to our original integrated Seurat object.

remerge <- merge(NKT, y=c(DCs, Bcells, ILCs, MM, Stromal, Mast, Neutrophils, ECs)) 
data.integrated <- AddMetaData(data.integrated, remerge$highlevel, col.name= "highlevel")

7.11 Correct identities

7.11.1 Endothelial to stromal

In later analysis, we reclassified endothelial cells as part of the major stromal cell cluster. To separate these changes from our original proprocessing, I designated these identities as lowlevel2

Idents(data.integrated) <- data.integrated$lowlevel
data.integrated <- RenameIdents(data.integrated, "Endothelial Cells" = "Stromal Cells")
data.integrated$lowlevel2 <- Idents(data.integrated)
data.integrated$lowlevel2 <- factor(data.integrated$lowlevel2, levels=c("Macrophages","Monocytes","Dendritic Cells","T Cells","NK Cells","B Cells","Plasma Cells","Mast Cells","Neutrophils","ILCs","Stromal Cells"))

7.11.2 Adjust highlevel subclusters

We also renamed some of the subclusters to clarify what these cell types are. Again, we gave these renamed clusters their own designation to avoid confusion with our preprocessing pipeline and called them highlevel2.

Idents(data.integrated) <- data.integrated$highlevel
data.integrated <- RenameIdents(data.integrated,
                                "Apoptotic Cell Clearance Macrophages" = "Efferocytes",
                                "gd T cells" = "gd T Cells",
                                "Proliferating Macrophages" = "Cycling Macrophages",
                                "Proliferating cDC2" = "Cycling cDC2",
                                "Proliferating cDC1" = "Cycling cDC1",
                                "Proliferating CD8+ T Cells" = "Cycling CD8+ T Cells",
                                "Effector CD8+ T Cells" = "Effector Memory CD8+ T Cells",
                                "Memory CD8+ T Cells" = "Central Memory CD8+ T Cells")
data.integrated$highlevel2 <- Idents(data.integrated)

7.11.3 Correct lowlevel and highlevel designations

For robustness, we also made sure that cells that are macrophage subclusters should be under the macrophage umbrella. This fixes some problems noted above, such as a mast cell population that was originally clustered in with the macrophages.

Idents(data.integrated) <- data.integrated$highlevel2

data.integrated$lowlevel2[WhichCells(data.integrated, idents=c("Tissue Resident Macrophages",
                                                               "LAMs",
                                                               "Cycling Macrophages",
                                                               "Efferocytes"))] <- "Macrophages"
data.integrated$lowlevel2[WhichCells(data.integrated, idents=c("Classical Monocytes",
                                                               "Non-classical Monocytes"))] <- "Monocytes"
data.integrated$lowlevel2[WhichCells(data.integrated, idents=c("cDC1",
                                                               "Activated cDC1","Cycling cDC1",
                                                               "cDC2",
                                                               "Activated cDC2",
                                                               "Cycling cDC2",
                                                               "pDCs",
                                                               "moDCs"))] <- "Dendritic Cells"
data.integrated$lowlevel2[WhichCells(data.integrated, idents=c("Th1 CD4+ T Cells",
                                                               "Th2 CD4+ T Cells",
                                                               "Tregs",
                                                               "Effector Memory CD8+ T Cells",
                                                               "Central Memory CD8+ T Cells",
                                                               "Cycling CD8+ T Cells",
                                                               "gd T Cells"))] <- "T Cells"
data.integrated$lowlevel2[WhichCells(data.integrated, idents=c("NKT Cells",
                                                               "NK Cells"))] <- "NK Cells"
data.integrated$lowlevel2[WhichCells(data.integrated, idents=c("Naive B Cells",
                                                               "Memory B Cells",
                                                               "B-1a Cells"))] <- "B Cells"
data.integrated$lowlevel2[WhichCells(data.integrated, idents=c("Plasma Cells"))] <- "Plasma Cells"
data.integrated$lowlevel2[WhichCells(data.integrated, idents=c("Mast Cells"))] <- "Mast Cells"
data.integrated$lowlevel2[WhichCells(data.integrated, idents=c("Neutrophils"))] <- "Neutrophils"
data.integrated$lowlevel2[WhichCells(data.integrated, idents=c("ILC2s"))] <- "ILCs"
data.integrated$lowlevel2[WhichCells(data.integrated, idents=c("Endothelial Cells",
                                                               "Adipocyte Precursor Cells",
                                                               "Mesothelial-like Cells"))] <- "Stromal Cells"

7.11.4 Reorder the identities

Finally, we reorder our identities, which makes downstream plotting much easier.

#Order levels of data.integrated
data.integrated$highlevel2 <- factor(data.integrated$highlevel2, 
                                     levels=c("Tissue Resident Macrophages",
                                              "LAMs",
                                              "Cycling Macrophages",
                                              "Efferocytes",
                                              "Classical Monocytes",
                                              "Non-classical Monocytes",
                                              "cDC1",
                                              "Activated cDC1",
                                              "Cycling cDC1",
                                              "cDC2",
                                              "Activated cDC2",
                                              "Cycling cDC2",
                                              "pDCs",
                                              "moDCs",
                                              "Th1 CD4+ T Cells",
                                              "Th2 CD4+ T Cells",
                                              "Tregs",
                                              "Effector Memory CD8+ T Cells",
                                              "Central Memory CD8+ T Cells",
                                              "Cycling CD8+ T Cells",
                                              "gd T Cells",
                                              "NK Cells",
                                              "NKT Cells",
                                              "Naive B Cells",
                                              "Memory B Cells",
                                              "B-1a Cells",
                                              "Plasma Cells",
                                              "Mast Cells",
                                              "Neutrophils",
                                              "ILC2s",
                                              "Endothelial Cells",
                                              "Adipocyte Precursor Cells",
                                              "Mesothelial-like Cells"))

8 Plot Cluster Annotations

8.1 Colors

First, assign the colors that we use throughout the study.

maccols <- brewer.pal(n=8, name="Blues")[c(-1,-3,-5,-7)]
monocols <- c("#ff8ade","#e324ad")
dccols <- brewer.pal(n=9, name="Greens")[-1]
tcols <- brewer.pal(n=8, name="Reds")[-1]
nkcols <- c("#876149","#6e3f22")
bcols <- brewer.pal(n=4, name="Purples")[-1]
othcols <- c("#71a157","#00c5cc","#a18e25","#b282b3")
strcols <- brewer.pal(n=4, name="Oranges")[-1]
wccols = c("#878787", "#518db6","#94cc73","#e96b53")

cols <- c(maccols,monocols,dccols,tcols,nkcols,bcols,othcols,strcols)

llcols <- c("#4292C6","#ff8ade","#238B45","#EF3B2C","#876149","#9E9AC8","#71a157","#00c5cc","#a18e25","#b282b3","#FD8D3C")

8.2 Plot Cell Types

DimPlot(data.integrated, group.by="lowlevel2", cols=llcols, label=T) + 
  NoLegend() + 
  labs(title="Cell Types")

8.3 Plot Subclusters

DimPlot(data.integrated, group.by="highlevel2", cols=cols) + 
  theme(legend.position="bottom", legend.text=element_text(size=7)) + 
  labs(title="Subclusters")

9 Save Progress

saveRDS(data.integrated, file="IntegratedData.RDS")

10 Session Info

sessionInfo()
R version 4.1.0 (2021-05-18)
Platform: x86_64-apple-darwin17.0 (64-bit)
Running under: macOS Big Sur 10.16

Matrix products: default
LAPACK: /Library/Frameworks/R.framework/Versions/4.1/Resources/lib/libRlapack.dylib

locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8

attached base packages:
[1] parallel  stats4    stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] formattable_0.2.1           celldex_1.2.0               SingleR_1.6.1               SummarizedExperiment_1.22.0
 [5] Biobase_2.52.0              GenomicRanges_1.44.0        GenomeInfoDb_1.28.0         IRanges_2.26.0             
 [9] S4Vectors_0.30.0            BiocGenerics_0.38.0         MatrixGenerics_1.4.0        matrixStats_0.59.0         
[13] clustree_0.4.3              ggraph_2.0.5                RColorBrewer_1.1-2          plotly_4.9.4.1             
[17] SeuratWrappers_0.3.0        cowplot_1.1.1               dplyr_1.0.7                 ggplot2_3.3.5              
[21] SeuratObject_4.0.2          Seurat_4.0.3               

loaded via a namespace (and not attached):
  [1] utf8_1.2.1                    reticulate_1.20               R.utils_2.10.1                tidyselect_1.1.1             
  [5] RSQLite_2.2.7                 AnnotationDbi_1.54.1          htmlwidgets_1.5.3             grid_4.1.0                   
  [9] BiocParallel_1.26.0           Rtsne_0.15                    munsell_0.5.0                 ScaledMatrix_1.0.0           
 [13] codetools_0.2-18              ica_1.0-2                     future_1.21.0                 miniUI_0.1.1.1               
 [17] withr_2.4.2                   colorspace_2.0-2              filelock_1.0.2                knitr_1.33                   
 [21] rstudioapi_0.13               SingleCellExperiment_1.14.1   ROCR_1.0-11                   tensor_1.5                   
 [25] listenv_0.8.0                 labeling_0.4.2                GenomeInfoDbData_1.2.6        polyclip_1.10-0              
 [29] bit64_4.0.5                   farver_2.1.0                  parallelly_1.27.0             vctrs_0.3.8                  
 [33] generics_0.1.0                xfun_0.24                     BiocFileCache_2.0.0           R6_2.5.0                     
 [37] graphlayouts_0.7.1            rsvd_1.0.5                    locfit_1.5-9.4                bitops_1.0-7                 
 [41] spatstat.utils_2.2-0          cachem_1.0.5                  DelayedArray_0.18.0           assertthat_0.2.1             
 [45] promises_1.2.0.1              scales_1.1.1                  gtable_0.3.0                  beachmat_2.8.0               
 [49] globals_0.14.0                goftest_1.2-2                 tidygraph_1.2.0               rlang_0.4.11                 
 [53] genefilter_1.74.0             splines_4.1.0                 lazyeval_0.2.2                spatstat.geom_2.2-2          
 [57] checkmate_2.0.0               BiocManager_1.30.16           yaml_2.2.1                    reshape2_1.4.4               
 [61] abind_1.4-5                   backports_1.2.1               httpuv_1.6.1                  tools_4.1.0                  
 [65] ellipsis_0.3.2                spatstat.core_2.3-0           jquerylib_0.1.4               ggridges_0.5.3               
 [69] Rcpp_1.0.7                    plyr_1.8.6                    sparseMatrixStats_1.4.0       zlibbioc_1.38.0              
 [73] purrr_0.3.4                   RCurl_1.98-1.3                rpart_4.1-15                  deldir_0.2-10                
 [77] pbapply_1.4-3                 viridis_0.6.1                 zoo_1.8-9                     ggrepel_0.9.1                
 [81] cluster_2.1.2                 tinytex_0.32                  magrittr_2.0.1                RSpectra_0.16-0              
 [85] data.table_1.14.0             scattermore_0.7               lmtest_0.9-38                 RANN_2.6.1                   
 [89] fitdistrplus_1.1-5            patchwork_1.1.1               mime_0.11                     evaluate_0.14                
 [93] xtable_1.8-4                  XML_3.99-0.6                  gridExtra_2.3                 compiler_4.1.0               
 [97] tibble_3.1.2                  KernSmooth_2.23-20            crayon_1.4.1                  R.oo_1.24.0                  
[101] htmltools_0.5.1.1             mgcv_1.8-36                   later_1.2.0                   geneplotter_1.70.0           
[105] tidyr_1.1.3                   DBI_1.1.1                     ExperimentHub_2.0.0           tweenr_1.0.2                 
[109] dbplyr_2.1.1                  rappdirs_0.3.3                MASS_7.3-54                   Matrix_1.3-4                 
[113] cli_3.0.1                     R.methodsS3_1.8.1             igraph_1.2.6                  pkgconfig_2.0.3              
[117] spatstat.sparse_2.0-0         annotate_1.70.0               bslib_0.2.5.1                 XVector_0.32.0               
[121] stringr_1.4.0                 digest_0.6.27                 sctransform_0.3.2             RcppAnnoy_0.0.18             
[125] Biostrings_2.60.1             spatstat.data_2.1-0           rmarkdown_2.9                 leiden_0.3.8                 
[129] uwot_0.1.10                   DelayedMatrixStats_1.14.0     curl_4.3.2                    shiny_1.6.0                  
[133] lifecycle_1.0.0               nlme_3.1-152                  jsonlite_1.7.2                BiocNeighbors_1.10.0         
[137] limma_3.48.0                  viridisLite_0.4.0             fansi_0.5.0                   pillar_1.6.1                 
[141] lattice_0.20-44               KEGGREST_1.32.0               fastmap_1.1.0                 httr_1.4.2                   
[145] survival_3.2-11               interactiveDisplayBase_1.30.0 glue_1.4.2                    remotes_2.4.0                
[149] png_0.1-7                     BiocVersion_3.13.1            bit_4.0.4                     ggforce_0.3.3                
[153] stringi_1.7.3                 sass_0.4.0                    blob_1.2.1                    DESeq2_1.32.0                
[157] AnnotationHub_3.0.1           BiocSingular_1.8.1            memoise_2.0.0                 ape_5.5                      
[161] irlba_2.3.3                   future.apply_1.7.0           
LS0tCnRpdGxlOiAiVmlnbmV0dGUgIzIgLSBDZWxsIEFubm90YXRpb24iCmF1dGhvcjogIk1hdHRoZXcgQS4gQ290dGFtIgpkYXRlOiAiOC84LzIwMjEiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OiAKICAgIHRvYzogeWVzCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcwogICAga2VlcF9tZDogdHJ1ZQogIGh0bWxfbm90ZWJvb2s6IAogICAgdGhlbWU6IHVuaXRlZAogICAgdG9jX2Zsb2F0OiB5ZXMKICAgIHRvYzogeWVzCiAgICBmaWdfaGVpZ2h0OiA2CiAgICBudW1iZXJfc2VjdGlvbnM6IHllcwotLS0KIyBJbiB0aGlzIHZpZ25ldHRlCgpJbiB0aGlzIGNlbGwgYW5ub3RhdGlvbiB2aWduZXR0ZSwgd2Ugd2lsbCBiZSB0YWtpbmcgdGhlIG91dHB1dCBmcm9tIHRoZSBEYXRhIEludGVncmF0aW9uIHZpZ25ldHRlIGFuZCBpZGVudGlmeWluZyBjZWxsIHR5cGVzIGFuZCBzdWJ0eXBlcyBieSBleHByZXNzaW9uIG9mIGtleSBtYXJrZXIgZ2VuZXMuIEhlcmVpbiwgd2Ugd2lsbCBkbyB0aGUgZm9sbG93aW5nOgoKMS4gUGVyZm9ybSBsb3ctcmVzb2x1dGlvbiBjbHVzdGVyaW5nCjIuIElkZW50aWZ5IGNlbGwgdHlwZXMgdXNpbmcgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkIGdlbmVzLgozLiBSZWNsdXN0ZXIgZWFjaCBjZWxsIHR5cGUgYXQgaGlnaGVyIHJlc29sdXRpb24uCjQuIElkZW50aWZ5IGNlbGwgc3VidHlwZXMgd2l0aGluIGJyb2FkIGNlbGwgdHlwZSBjbHVzdGVycyB1c2luZyBkaWZmZXJlbnRpYWxseSBleHByZXNzZWQgZ2VuZXMuCjUuIFJ1biBTaW5nbGVSIHRvIGhlbHAgY29uZmlybSBhbm5vdGF0aW9ucy4KCiMgUHJlcGFyZSB0aGUgUiBlbnZpcm9ubWVudAoKIyMgTG9hZCBpbiB0aGUgbmVjZXNzYXJ5IGxpYnJhcmllcwoKYGBge3Igc2V0dXAsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmxpYnJhcnkoU2V1cmF0KQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoY293cGxvdCkKbGlicmFyeShTZXVyYXRXcmFwcGVycykKbGlicmFyeShwbG90bHkpCmxpYnJhcnkoUkNvbG9yQnJld2VyKQpsaWJyYXJ5KGNsdXN0cmVlKQpsaWJyYXJ5KFNpbmdsZVIpCmxpYnJhcnkoZm9ybWF0dGFibGUpCmBgYAoKIyMgTG9hZCBpbiBvdXIgU2V1cmF0IG9iamVjdAoKVGhpcyBgLnJkc2AgZmlsZSBjb21lcyBmcm9tIFZpZ25ldHRlICMyIC0gRGF0YSBJbnRlZ3JhdGlvbi4KCmBgYHtyIHJlYWRkYXRhfQpkYXRhLmludGVncmF0ZWQgPC0gcmVhZFJEUygiLi4vMl9EYXRhSW50ZWdyYXRpb25fVmlnbmV0dGUvMl9EYXRhSW50ZWdyYXRpb24ucmRzIikKYGBgCgojIENsdXN0ZXJpbmcgYW5kIHZpc3VhbGl6YXRpb24KClNldXJhdCB1c2VzIEstbmVhcmVzdCBuZWlnaGJvciBjbHVzdGVyaW5nIGJhc2VkIG9uIFBDQSBhbmQgdGhlbiBjbHVzdGVycyB0aGUgY2VsbHMgdXNpbmcgdGhlIExvdXZhaW4gYWxnb3JpdGhtLiBOZWFyZXN0IG5laWdoYm9yIGNsdXN0ZXJpbmcgcmVxdWlyZXMgaW5wdXQgb2YgZGltZW5zaW9ucy4gQmFzZWQgb24gdGhlIGBKYWNrU3RyYXdQbG90YCBhbmQgYEVsYm93UGxvdGAsIHdlIHdpbGwgdXNlIGFsbCA1MCBQQ3MgYW5kIGNvdWxkIGxpa2VseSB1c2UgZXZlbiBtb3JlLiBIb3dldmVyLCBpdCBpcyBub3RlZCB0aGF0IHRoZXJlIGFyZSBkaW1pbmlzaGluZyByZXR1cm5zIG9uIHRoZSBudW1iZXIgb2YgUENzLCBzbyA1MCB3aWxsIGJlIHN1ZmZpY2llbnQuCgpgYGB7ciBrbm59CmRhdGEuaW50ZWdyYXRlZCA8LSBGaW5kTmVpZ2hib3JzKGRhdGEuaW50ZWdyYXRlZCwgZGltcz0xOjUwKSAKYGBgCgojIyBDbHVzdHJlZQoKUmVzb2x1dGlvbiBvZiB0aGUgTG91dmFpbiBjbHVzdGVyaW5nIGFsZ29yaXRobSBncmVhdGx5IGFmZmVjdHMgbnVtYmVyIG9mIGlkZW50aWZpZWQgY2x1c3RlcnMuIFRoaXMgY2FuIGJlIHZpc3VhbGl6ZWQgYnkgaXRlcmF0aW5nIG92ZXIgbXVsdGlwbGUgcmVzb2x1dGlvbnMgYW5kIHRoZW4gcGxvdHRpbmcgdXNpbmcgQ2x1c3RyZWUuIFRoZSByZXN1bHRpbmcgY2x1c3RlcmluZyBpcyBzdG9yZWQgaW4gdGhlIG1ldGFEYXRhIG9mIG91ciBpbnRlZ3JhdGVkIFNldXJhdCBvYmplY3QuCgpgYGB7ciBjbHVzdHJlZSwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTEyfQojQ2FsY3VsYXRlIGNsdXN0ZXJzIGZvciBhIG51bWJlciBvZiByZXNvbHV0aW9ucyByYW5naW5nIGZyb20gMC4yLTEuMApyZXMgPC0gYygwLjIsMC4zLDAuNCwwLjUsMC42LDAuNywwLjgsMC45LDEuMCkKZGF0YS5pbnRlZ3JhdGVkIDwtIEZpbmRDbHVzdGVycyhkYXRhLmludGVncmF0ZWQsIHJlc29sdXRpb249cmVzKQojUGxvdCB1c2luZyBDbHVzdHJlZQpjbHVzdHJlZShkYXRhLmludGVncmF0ZWQsIHByZWZpeD0iaW50ZWdyYXRlZF9zbm5fcmVzLiIpCmBgYAoKYGBge3IgcmVjbHVzdH0KI1JlY2x1c3RlciBhdCB0aGUgc2VsZWN0ZWQgcmVzb2x1dGlvbiBvZiBpbnRlcmVzdC4gVGhpcyBpcyBub3QgYWJzb2x1dGVseSBuZWNlc3NhcnksIGJ1dCBpcyBhIG5pY2UgcmVkdW5kYW5jeSBhbmQgcmVzZXRzIHRoZSBgc2V1cmF0X2NsdXN0ZXJzYCBjb2x1bW4gaW4gdGhlIG1ldGFkYXRhIGF1dG9tYXRpY2FsbHkuCmRhdGEuaW50ZWdyYXRlZCA8LSBGaW5kQ2x1c3RlcnMoZGF0YS5pbnRlZ3JhdGVkLCByZXNvbHV0aW9uPTAuNCkKYGBgCgojIFNpbmdsZVIKVGhlIFIgcGFja2FnZSBgU2luZ2xlUmAgdXNlcyBtaWNyb2FycmF5IHJlZmVyZW5jZSBkYXRhc2V0cyB0byBhdHRlbXB0IHRvIGFubm90YXRlIGVhY2ggaW5kaXZpZHVhbCBjZWxsLiBXZSB3aWxsIHVzZSB0aGlzIHBhY2thZ2UgYXMgYSB0b29sIHRvIHN1cHBvcnQgY2x1c3RlciBpZGVudGlmaWNhdGlvbi4gaHR0cHM6Ly9iaW9jb25kdWN0b3Iub3JnL3BhY2thZ2VzL3JlbGVhc2UvYmlvYy9odG1sL1NpbmdsZVIuaHRtbCBSZWZlcmVuY2VzIGZvciBgU2luZ2xlUmAgYXJlIHByb3ZpZGVkIGJ5IHRoZSBwb2tlZGV4IGZvciBjZWxscyBgY2VsbGRleC5gIEluIHRoaXMgY2FzZSwgd2Ugd2lsbCBydW4gYFNpbmdsZXJSYCB3aXRoIHR3byBkaWZmZXJlbnQgZGF0YWJhc2VzOiAxKSBJbW1nZW4gYW5kIDIpIE1vdXNlUk5Bc2VxIGZyb20gdGhlIGdlbmUgZXhwcmVzc2lvbiBvbW5pYnVzLgoKYGBge3Igc2luZ2xlciwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTR9CiNXYXJuaW5nLCB0aGlzIHRha2VzIGEgdmVyeSBsb25nIHRpbWUgdG8gcnVuIGFuZCBzY2FsZXMgcG9vcmx5IHdpdGggbnVtYmVyIG9mIGNlbGxzLCBidXQgaXMgbm90IGNvbXB1dGF0aW9uYWxseSBleHBlbnNpdmUgKGNhbiBydW4gd2l0aCA4IGdiIG9mIFJBTS4KI0xvYWQgaW4gdGhlIGRhdGFiYXNlIGluZm9ybWF0aW9uCkltbUdlbiA8LSBJbW1HZW5EYXRhKCkgCk1vdXNlUk5Bc2VxIDwtIE1vdXNlUk5Bc2VxRGF0YSgpCiNTaW5nbGVSIHJlcXVpcmVzIGNvbnZlcnNpb24gdG8gYSBzaW5nbGUgY2VsbCBleHBlcmltZW50IG9iamVjdApzaW5nbGVSIDwtIGFzLlNpbmdsZUNlbGxFeHBlcmltZW50KGRhdGEuaW50ZWdyYXRlZCwgYXNzYXk9ICJpbnRlZ3JhdGVkIikgCiNDcmVhdGUgbWFpbiBsYWJlbHMgdXNpbmcgdGhlIEltbWdlbiBkYXRhYmFzZQpzaW5nbGVyLkltbUdlbiA8LSBTaW5nbGVSKHRlc3QgPSBzaW5nbGVSLCByZWYgPSBJbW1HZW4sIGxhYmVscyA9IChJbW1HZW4kbGFiZWwubWFpbikpCiNDcmVhdGUgbWFpbiBsYWJlbHMgdXNpbmcgdGhlIEltbWdlbiBkYXRhYmFzZQpzaW5nbGVyLk1vdXNlUk5Bc2VxIDwtIFNpbmdsZVIodGVzdCA9IHNpbmdsZVIsIHJlZiA9IE1vdXNlUk5Bc2VxLCBsYWJlbHMgPSAoTW91c2VSTkFzZXEkbGFiZWwubWFpbikpCiNTYXZlIHRoZSBzaW5nbGVSIGxhYmVscyBpbnRvIG91ciBTZXVyYXQgb2JqZWN0IGFzIGEgbWV0YURhdGEgY29sdW1uCmRhdGEuaW50ZWdyYXRlZFtbIkltbUdlbiJdXSA8LSBzaW5nbGVyLkltbUdlbiRsYWJlbHMgCmRhdGEuaW50ZWdyYXRlZFtbIk1vdXNlUk5Bc2VxZGIiXV0gPC0gc2luZ2xlci5Nb3VzZVJOQXNlcSRsYWJlbHMKI1Bsb3QgdGhlIG1haW4gbGFiZWxzIGFuZCBjb21wYXJlIHRoZW0gdG8gdGhlIG9yaWdpbmFsIFNldXJhdCBjbHVzdGVycwpTUjEgPC0gRGltUGxvdChkYXRhLmludGVncmF0ZWQsIGxhYmVsPVQsIHJlcGVsPVQpICsgTm9MZWdlbmQoKQpTUjIgPC0gRGltUGxvdChkYXRhLmludGVncmF0ZWQsIGxhYmVsPVQsIHJlcGVsPVQsIGdyb3VwLmJ5PSJJbW1HZW4iKSArIE5vTGVnZW5kKCkKU1IzIDwtIERpbVBsb3QoZGF0YS5pbnRlZ3JhdGVkLCBsYWJlbD1ULCByZXBlbD1ULCBncm91cC5ieT0iTW91c2VSTkFzZXFkYiIpICsgTm9MZWdlbmQoKQpTUjEgKyBTUjIgKyBTUjMKYGBgCgojIExvdy1sZXZlbCBDbHVzdGVyIElkZW50aWZpY2F0aW9uClNldXJhdCBoYXMgYSBidWlsdCBpbiBmdW5jdGlvbiBmb3IgZGlmZmVyZW50aWFsIGV4cHJlc3Npb24gYWNyb3NzIGlkZW50aXRpZXMuIEluIHRoaXMgY2FzZSwgb3VyIGlkZW50aXRpZXMgYXJlIGN1cnJlbnRseSBudW1iZXJlZCBjbHVzdGVycyBhbmQgc2V0dGluZyBGaW5kQWxsTWFya2VycyB0byByZXBvcnQgb25seSBnZW5lcyBleHByZXNzaW9uIGluIGF0IGxlYXN0IDUwJSBvZiBjZWxscyAoZm9yIGEgZ2l2ZW4gY2x1c3RlcikgYW5kIHdpdGggYSBwb3NpdGl2ZSBmb2xkIGNoYW5nZSB3aWxsIGdpdmUgdXMgbWFya2VycyB0aGF0IGFyZSBoaWdobHkgZXhwcmVzc2VkIHdpdGhpbiBlYWNoIGNsdXN0ZXIuIFRoZSBtYXguY2VsbHMucGVyLmlkZW50IG9wdGlvbiBsaW1pdHMgdGhlIGFtb3VudCBvZiBjZWxscyBpbmNsdWRlZCB0byByZWR1Y2UgY29tcHV0YXRpb25hbCB0aW1lLgoKYGBge3IgbGxjbHVzdGVybWFya2Vyc30KbG93bGV2ZWwubWFya2VycyA8LSBGaW5kQWxsTWFya2VycyhkYXRhLmludGVncmF0ZWQsIG9ubHkucG9zID0gVFJVRSwgbWluLnBjdCA9IDAuNTAsIGxvZ2ZjLnRocmVzaG9sZCA9IDAuMjUsIG1heC5jZWxscy5wZXIuaWRlbnQ9MTAwMCwgdmVyYm9zZT1GQUxTRSkKCiNTdG9yZSB0aGUgdG9wMTAgbWFya2VycyBmb3IgZWFjaCBjbHVzdGVyIGFuZCB3cml0ZSBpdCB0byBhIHRhYmxlCnRvcDEwIDwtIGxvd2xldmVsLm1hcmtlcnMgJT4lIGdyb3VwX2J5KGNsdXN0ZXIpICU+JSB0b3BfbihuID0gMTAsIHd0ID0gYXZnX2xvZzJGQykKCiNQdXQgdGhlIHRvcDEwIG1hcmtlcnMgZm9yIGVhY2ggY2x1c3RlciBpbnRvIGEgZm9ybWF0dGVkIHRhYmxlCnRvcDEwICU+JSBmb3JtYXR0YWJsZSgpCmBgYAoKIyMgUmVuYW1lIGxvdy1sZXZlbCBpZGVudGl0aWVzClVzaW5nIHRoZSBhbm5vdGF0aW9ucyBmcm9tIFNpbmdsZVIgYW5kIHRoZSBkaWZmZXJlbnRpYWxseSBleHByZXNzZWQgZ2VuZXMsIHdlIGNhbiBhc3NpZ24gYW5ub3RhdGlvbnMgdG8gZWFjaCBjZWxsIHR5cGUgY2x1c3Rlci4gRm9yIHRoaXMsIHdlIGhlYXZpbHkgcmVmZXJlbmNlIGxpdGVyYXR1cmUgYW5kIHNlZWsgdG8gaWRlbnRpZnkga25vd24gY2VsbCB0eXBlIG1hcmtlciBnZW5lcy4gV2Ugd2lsbCBmdXJ0aGVyIHJlZmluZSBhbmQgYWRqdXN0IHRoZXNlIHJlc3VsdHMgd2hlbiB3ZSBoYXZlIG1vcmUgZ3JhbnVsYXIgY2VsbCB0eXBlIGFubm90YXRpb25zIGFmdGVyIHN1YmNsdXN0ZXJpbmcuCgpgYGB7ciByZW5hbWVsbGNsdXN0ZXJzfQojUmVuYW1lIGNsdXN0ZXJzIGJhc2VkIG9uIHRoZWlyIGRlZHVjZWQgaWRlbnRpdGllcwpkYXRhLmludGVncmF0ZWQgPC0gUmVuYW1lSWRlbnRzKGRhdGEuaW50ZWdyYXRlZCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnMCcgPSAiTWFjcm9waGFnZXMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICcxJyA9ICJNYWNyb3BoYWdlcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJzInID0gIk1vbm9jeXRlcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJzMnID0gIkIgQ2VsbHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICc0JyA9ICJNYWNyb3BoYWdlcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJzUnID0gIkRlbmRyaXRpYyBDZWxscyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJzYnID0gIkRlbmRyaXRpYyBDZWxscyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJzcnID0gIlQgQ2VsbHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICc4JyA9ICJOSyBDZWxscyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJzknID0gIlN0cm9tYWwgQ2VsbHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICcxMCcgPSAiVCBDZWxscyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJzExJyA9ICJUIENlbGxzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnMTInID0gIk1hY3JvcGhhZ2VzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnMTMnID0gIlQgQ2VsbHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICcxNCcgPSAiSUxDcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJzE1JyA9ICJEZW5kcml0aWMgQ2VsbHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICcxNicgPSAiTW9ub2N5dGVzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnMTcnID0gIlBsYXNtYSBDZWxscyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJzE4JyA9ICJUIENlbGxzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnMTknID0gIk1hc3QgQ2VsbHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICcyMCcgPSAiRGVuZHJpdGljIENlbGxzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnMjEnID0gIlBsYXNtYSBDZWxscyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJzIyJyA9ICJTdHJvbWFsIENlbGxzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnMjMnID0gIk5ldXRyb3BoaWxzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnMjQnID0gIkIgQ2VsbHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICcyNScgPSAiRW5kb3RoZWxpYWwgQ2VsbHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICcyNicgPSAiTWFjcm9waGFnZXMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICcyNycgPSAiRGVuZHJpdGljIENlbGxzIikKYGBgCgojIFBsb3QgbG93bGV2ZWwgY2x1c3RlcnMKCmBgYHtyIGxsY2x1c3RlcnMsIGZpZy53aWR0aD02LCBmaWcuaGVpZ2h0PTZ9CiNTYXZlIGFuZCBwbG90IHRoZSBsb3cgbGV2ZWwgaWRlbnRpZmljYXRpb24KZGF0YS5pbnRlZ3JhdGVkJGxvd2xldmVsIDwtIElkZW50cyhkYXRhLmludGVncmF0ZWQpCkRpbVBsb3QoZGF0YS5pbnRlZ3JhdGVkLCBsYWJlbD1UKSArIE5vTGVnZW5kKCkKYGBgCgojIEhpZ2gtbGV2ZWwgQ2x1c3RlciBJZGVudGlmaWNhdGlvbgoKRm9yIGVhY2ggb2YgdGhlIDEyIGNlbGwgdHlwZSBjbHVzdGVycywgd2Ugd2lsbCBzdWJzZXQgdGhlIGNlbGxzIGFuZCByZXBlYXQgY2x1c3RlcmluZyB0byBkZWZpbmUgc3ViY2x1c3RlcnMuIEluIHRoaXMgdmlnbmV0dGUsIHdlIHJlZmVyIHRvIHRoZXNlIHN1YmNsdXN0ZXJzIGFzIGhpZ2gtcmVzb2x1dGlvbiBvciBoaWdoLWxldmVsIGNsdXN0ZXJzLgoKIyMgVCBhbmQgTksgQ2VsbHMKCiMjIyBQQ0EgYW5kIGNsdXN0ZXJpbmcKClJ1biBQQ0EgYW5kIGRldGVybWluZSBkaW1lbnNpb25zIGZvciBjbHVzdGVyaW5nLgoKYGBge3IgTktUUENBLCBmaWcud2lkdGg9MywgZmlnLmhlaWdodD0zfQpOS1QgPC0gc3Vic2V0KGRhdGEuaW50ZWdyYXRlZCwgaWRlbnRzID0gYygiVCBDZWxscyIsICJOSyBDZWxscyIpKQpOS1QgPC0gUnVuUENBKE5LVCwgZmVhdHVyZXM9VmFyaWFibGVGZWF0dXJlcyhOS1QpLGRpbXM9MTozMCwgdmVyYm9zZT1GQUxTRSkKRWxib3dQbG90KE5LVCwgbmRpbXM9MzAsIHJlZHVjdGlvbj0icGNhIikKYGBgCgpHZW5lcmF0ZSBhIGNsdXN0ZXJpbmcgdHJlZSBhbmQgZGV0ZXJtaW5lIGNsdXN0ZXJpbmcgcmVzb2x1dGlvbiBmb3Igc3ViY2x1c3RlcnMuCgpgYGB7ciBOS1RjbHVzdHJlZSwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTEyfQpOS1QgPC0gRmluZE5laWdoYm9ycyhOS1QsIGRpbXM9MToxNSwgdmVyYm9zZT1GQUxTRSkgCk5LVCA8LSBGaW5kQ2x1c3RlcnMoTktULCByZXNvbHV0aW9uPXJlcywgdmVyYm9zZT1GQUxTRSkgCgojIENsdXN0ZXJpbmcgVHJlZQpjbHVzdHJlZShOS1QsIHByZWZpeD0iaW50ZWdyYXRlZF9zbm5fcmVzLiIpIAoKIyBDaG9vc2UgcmVzb2x1dGlvbgpOS1QgPC0gRmluZENsdXN0ZXJzKE5LVCwgcmVzb2x1dGlvbj0wLjMxLCB2ZXJib3NlPUZBTFNFKSAKYGBgCgojIyMgRGltZW5zaW9uYWwgUmVkdWN0aW9uCgpQbG90IHRoZSBkaW1lbnNpb25hbCByZWR1Y3Rpb24gZm9yIHRoZSBuZXcgY2VsbCBzdWJjbHVzdGVycy4KCmBgYHtyIE5LVGRyLCBmaWcud2lkdGg9NiwgZmlnLmhlaWdodD02fQojIFJ1biBVTUFQCk5LVCA8LSBSdW5VTUFQKE5LVCwgZGltcz0xOjE1LCB2ZXJib3NlPUZBTFNFKSAKCiMgUGxvdCBVTUFQCkRpbVBsb3QoTktULCByZWR1Y3Rpb249InVtYXAiLCBsYWJlbD1UUlVFKSArIE5vTGVnZW5kKCkgCmBgYAoKIyMjIEZpbmQgU3ViY2x1c3RlciBNYXJrZXJzCgpGaW5kIGRpZmZlcmVudGlhbGx5IGV4cHJlc3NlZCBtYXJrZXJzIGJldHdlZW4gdGhlIHN1YmNsdXN0ZXJzLgoKYGBge3IgTktUZmluZG1hcmtlcnN9CiMgRmluZCBNYXJrZXJzCk5LVC5tYXJrZXJzIDwtIEZpbmRBbGxNYXJrZXJzKE5LVCwgb25seS5wb3MgPSBUUlVFLCBtaW4ucGN0ID0gMC41MCwgbG9nZmMudGhyZXNob2xkID0gMC4yNSwgbWF4LmNlbGxzLnBlci5pZGVudD01MDAsIHZlcmJvc2U9RkFMU0UpIAoKIyBMaXN0IHRvcCAxMCBnZW5lcyBmb3IgZWFjaCBzdWJjbHVzdGVyIGluIGEgdGFibGUKTktULm1hcmtlcnMudG9wMTAgPC0gTktULm1hcmtlcnMgJT4lIGdyb3VwX2J5KGNsdXN0ZXIpICU+JSB0b3BfbihuID0gMTAsIHd0ID0gYXZnX2xvZzJGQykKTktULm1hcmtlcnMudG9wMTAgJT4lIGZvcm1hdHRhYmxlKCkKYGBgCgojIyMgUmVuYW1lIHN1YmNsdXN0ZXIgaWRlbnRpdGllcwoKVXNpbmcgdGhlIGluZm9ybWF0aW9uIGZyb20gU2luZ2xlUiBhbmQgZGlmZmVyZW50aWFsIGV4cHJlc3Npb24sIGFzc2lnbiBhbm5vdGF0aW9ucyB0byB0aGUgc3ViY2x1c3RlcnMuCgpgYGB7ciBOS1RyZW5hbWVpZGVudHN9Ck5LVCA8LSBSZW5hbWVJZGVudHMoTktULAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJzAnID0gIk5LIENlbGxzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICcxJyA9ICJFZmZlY3RvciBDRDgrIFQgQ2VsbHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJzInID0gIlRoMSBDRDQrIFQgQ2VsbHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJzMnID0gIk5LVCBDZWxscyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnNCcgPSAiZ2QgVCBjZWxscyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnNScgPSAiTWVtb3J5IENEOCsgVCBDZWxscyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnNicgPSAiVHJlZ3MiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJzcnID0gIlByb2xpZmVyYXRpbmcgQ0Q4KyBUIENlbGxzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICc4JyA9ICJUaDIgQ0Q0KyBUIENlbGxzIikKTktUJGhpZ2hsZXZlbCA8LSBJZGVudHMoTktUKQpgYGAKCiMjIyBGaW5hbCBEaW0gUGxvdAoKQXMgYSBmaW5hbCBjaGVjaywgdGFrZSBhIGxvb2sgYXQgdGhlIERpbSBQbG90IGZvciB0aGUgc3ViY2x1c3RlcnMgYW5kIGNvbmZpcm0gdGhhdCBpdCBtYWtlcyBzZW5zZS4KCmBgYHtyIE5LVHBsb3QsIGZpZy53aWR0aD02LCBmaWcuaGVpZ2h0PTZ9CkRpbVBsb3QoTktULCByZWR1Y3Rpb249InVtYXAiLCBncm91cC5ieT0iaGlnaGxldmVsIiwgbGFiZWw9VFJVRSwgcmVwZWw9VFJVRSkgKyBOb0xlZ2VuZCgpICsgbGFicyh0aXRsZT0iTksgYW5kIFQgQ2VsbHMiKQpgYGAKCgoKIyMgRGVuZHJpdGljIENlbGxzCgojIyMgUENBIGFuZCBjbHVzdGVyaW5nCgpSdW4gUENBIGFuZCBkZXRlcm1pbmUgZGltZW5zaW9ucyBmb3IgY2x1c3RlcmluZy4KCmBgYHtyIERDUENBLCBmaWcud2lkdGg9MywgZmlnLmhlaWdodD0zfQpEQ3MgPC0gc3Vic2V0KGRhdGEuaW50ZWdyYXRlZCwgaWRlbnRzID0gYygiRGVuZHJpdGljIENlbGxzIikpCkRDcyA8LSBSdW5QQ0EoRENzLCBmZWF0dXJlcz1WYXJpYWJsZUZlYXR1cmVzKERDcyksZGltcz0xOjMwLCB2ZXJib3NlPUZBTFNFKQpFbGJvd1Bsb3QoRENzLCBuZGltcz0zMCwgcmVkdWN0aW9uPSJwY2EiKQpgYGAKCkdlbmVyYXRlIGEgY2x1c3RlcmluZyB0cmVlIGFuZCBkZXRlcm1pbmUgY2x1c3RlcmluZyByZXNvbHV0aW9uIGZvciBzdWJjbHVzdGVycy4KCmBgYHtyIERDY2x1c3RyZWUsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD0xMn0KRENzIDwtIEZpbmROZWlnaGJvcnMoRENzLCBkaW1zPTE6MTUsIHZlcmJvc2U9RkFMU0UpIApEQ3MgPC0gRmluZENsdXN0ZXJzKERDcywgcmVzb2x1dGlvbj1yZXMsIHZlcmJvc2U9RkFMU0UpIAoKIyBDbHVzdGVyaW5nIFRyZWUKY2x1c3RyZWUoRENzLCBwcmVmaXg9ImludGVncmF0ZWRfc25uX3Jlcy4iKSAKCiMgQ2hvb3NlIHJlc29sdXRpb24KRENzIDwtIEZpbmRDbHVzdGVycyhEQ3MsIHJlc29sdXRpb249MC4zLCB2ZXJib3NlPUZBTFNFKSAKYGBgCgojIyMgRGltZW5zaW9uYWwgUmVkdWN0aW9uCgpQbG90IHRoZSBkaW1lbnNpb25hbCByZWR1Y3Rpb24gZm9yIHRoZSBuZXcgY2VsbCBzdWJjbHVzdGVycy4KCmBgYHtyIERDZHIsIGZpZy53aWR0aD02LCBmaWcuaGVpZ2h0PTZ9CiMgUnVuIFVNQVAKRENzIDwtIFJ1blVNQVAoRENzLCBkaW1zPTE6MTUsIHZlcmJvc2U9RkFMU0UpIAoKIyBQbG90IFVNQVAKRGltUGxvdChEQ3MsIHJlZHVjdGlvbj0idW1hcCIsIGxhYmVsPVRSVUUpICsgTm9MZWdlbmQoKSAKYGBgCgojIyMgRmluZCBTdWJjbHVzdGVyIE1hcmtlcnMKCkZpbmQgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkIG1hcmtlcnMgYmV0d2VlbiB0aGUgc3ViY2x1c3RlcnMuCgpgYGB7ciBEQ2ZpbmRtYXJrZXJzfQojIEZpbmQgTWFya2VycwpEQ3MubWFya2VycyA8LSBGaW5kQWxsTWFya2VycyhEQ3MsIG9ubHkucG9zID0gVFJVRSwgbWluLnBjdCA9IDAuNTAsIGxvZ2ZjLnRocmVzaG9sZCA9IDAuMjUsIG1heC5jZWxscy5wZXIuaWRlbnQ9NTAwLCB2ZXJib3NlPUZBTFNFKSAKCiMgTGlzdCB0b3AgMTAgZ2VuZXMgZm9yIGVhY2ggc3ViY2x1c3RlciBpbiBhIHRhYmxlCkRDcy5tYXJrZXJzLnRvcDEwIDwtIERDcy5tYXJrZXJzICU+JSBncm91cF9ieShjbHVzdGVyKSAlPiUgdG9wX24obiA9IDEwLCB3dCA9IGF2Z19sb2cyRkMpCkRDcy5tYXJrZXJzLnRvcDEwICU+JSBmb3JtYXR0YWJsZSgpCmBgYAoKIyMjIFJlbmFtZSBzdWJjbHVzdGVyIGlkZW50aXRpZXMKClVzaW5nIHRoZSBpbmZvcm1hdGlvbiBmcm9tIFNpbmdsZVIgYW5kIGRpZmZlcmVudGlhbCBleHByZXNzaW9uLCBhc3NpZ24gYW5ub3RhdGlvbnMgdG8gdGhlIHN1YmNsdXN0ZXJzLgoKYGBge3IgRENzcmVuYW1laWRlbnRzfQpEQ3MgPC0gUmVuYW1lSWRlbnRzKERDcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICcwJyA9ICJjREMxIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICcxJyA9ICJjREMyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICcyJyA9ICJtb0RDcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnMycgPSAiQWN0aXZhdGVkIGNEQzIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJzQnID0gImNEQzEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJzUnID0gIlByb2xpZmVyYXRpbmcgY0RDMSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnNicgPSAiY0RDMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnNycgPSAiUHJvbGlmZXJhdGluZyBjREMyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICc4JyA9ICJQcm9saWZlcmF0aW5nIGNEQzEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJzknID0gIkFjdGl2YXRlZCBjREMxIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICcxMCcgPSAicERDcyIpCkRDcyRoaWdobGV2ZWwgPC0gSWRlbnRzKERDcykKYGBgCgojIyMgRmluYWwgRGltIFBsb3QKCkFzIGEgZmluYWwgY2hlY2ssIHRha2UgYSBsb29rIGF0IHRoZSBEaW0gUGxvdCBmb3IgdGhlIHN1YmNsdXN0ZXJzIGFuZCBjb25maXJtIHRoYXQgaXQgbWFrZXMgc2Vuc2UuCgpgYGB7ciBEQ3Bsb3QsIGZpZy53aWR0aD02LCBmaWcuaGVpZ2h0PTZ9CkRpbVBsb3QoRENzLCByZWR1Y3Rpb249InVtYXAiLCBncm91cC5ieT0iaGlnaGxldmVsIiwgbGFiZWw9VFJVRSwgcmVwZWw9VFJVRSkgKyBOb0xlZ2VuZCgpICsgbGFicyh0aXRsZT0iRGVuZHJpdGljIENlbGxzIikKYGBgCgoKCiMjIEIgYW5kIFBsYXNtYSBDZWxscwoKIyMjIFBDQSBhbmQgY2x1c3RlcmluZwoKUnVuIFBDQSBhbmQgZGV0ZXJtaW5lIGRpbWVuc2lvbnMgZm9yIGNsdXN0ZXJpbmcuCgpgYGB7ciBCUENBLCBmaWcud2lkdGg9MywgZmlnLmhlaWdodD0zfQpCY2VsbHMgPC0gc3Vic2V0KGRhdGEuaW50ZWdyYXRlZCwgaWRlbnRzID0gYygiQiBDZWxscyIsIlBsYXNtYSBDZWxscyIpKQpCY2VsbHMgPC0gUnVuUENBKEJjZWxscywgZmVhdHVyZXM9VmFyaWFibGVGZWF0dXJlcyhCY2VsbHMpLGRpbXM9MTozMCwgdmVyYm9zZT1GQUxTRSkKRWxib3dQbG90KEJjZWxscywgbmRpbXM9MzAsIHJlZHVjdGlvbj0icGNhIikKYGBgCgpHZW5lcmF0ZSBhIGNsdXN0ZXJpbmcgdHJlZSBhbmQgZGV0ZXJtaW5lIGNsdXN0ZXJpbmcgcmVzb2x1dGlvbiBmb3Igc3ViY2x1c3RlcnMuCgpgYGB7ciBCY2x1c3RyZWUsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD0xMn0KQmNlbGxzIDwtIEZpbmROZWlnaGJvcnMoQmNlbGxzLCBkaW1zPTE6MTAsIHZlcmJvc2U9RkFMU0UpIApCY2VsbHMgPC0gRmluZENsdXN0ZXJzKEJjZWxscywgcmVzb2x1dGlvbj1yZXMsIHZlcmJvc2U9RkFMU0UpIAoKIyBDbHVzdGVyaW5nIFRyZWUKY2x1c3RyZWUoQmNlbGxzLCBwcmVmaXg9ImludGVncmF0ZWRfc25uX3Jlcy4iKSAKCiMgQ2hvb3NlIHJlc29sdXRpb24KQmNlbGxzIDwtIEZpbmRDbHVzdGVycyhCY2VsbHMsIHJlc29sdXRpb249MC4yLCB2ZXJib3NlPUZBTFNFKSAKYGBgCgojIyMgRGltZW5zaW9uYWwgUmVkdWN0aW9uCgpQbG90IHRoZSBkaW1lbnNpb25hbCByZWR1Y3Rpb24gZm9yIHRoZSBuZXcgY2VsbCBzdWJjbHVzdGVycy4KCmBgYHtyIEJkciwgZmlnLndpZHRoPTYsIGZpZy5oZWlnaHQ9Nn0KIyBSdW4gVU1BUApCY2VsbHMgPC0gUnVuVU1BUChCY2VsbHMsIGRpbXM9MToxMCwgdmVyYm9zZT1GQUxTRSkgCgojIFBsb3QgVU1BUApEaW1QbG90KEJjZWxscywgcmVkdWN0aW9uPSJ1bWFwIiwgbGFiZWw9VFJVRSkgKyBOb0xlZ2VuZCgpIApgYGAKCiMjIyBGaW5kIFN1YmNsdXN0ZXIgTWFya2VycwoKRmluZCBkaWZmZXJlbnRpYWxseSBleHByZXNzZWQgbWFya2VycyBiZXR3ZWVuIHRoZSBzdWJjbHVzdGVycy4KCmBgYHtyIEJmaW5kbWFya2Vyc30KIyBGaW5kIE1hcmtlcnMKQmNlbGxzLm1hcmtlcnMgPC0gRmluZEFsbE1hcmtlcnMoQmNlbGxzLCBvbmx5LnBvcyA9IFRSVUUsIG1pbi5wY3QgPSAwLjUwLCBsb2dmYy50aHJlc2hvbGQgPSAwLjI1LCBtYXguY2VsbHMucGVyLmlkZW50PTUwMCwgdmVyYm9zZT1GQUxTRSkgCgojIExpc3QgdG9wIDEwIGdlbmVzIGZvciBlYWNoIHN1YmNsdXN0ZXIgaW4gYSB0YWJsZQpCY2VsbHMubWFya2Vycy50b3AxMCA8LSBCY2VsbHMubWFya2VycyAlPiUgZ3JvdXBfYnkoY2x1c3RlcikgJT4lIHRvcF9uKG4gPSAxMCwgd3QgPSBhdmdfbG9nMkZDKQpCY2VsbHMubWFya2Vycy50b3AxMCAlPiUgZm9ybWF0dGFibGUoKQpgYGAKCiMjIyBSZW5hbWUgc3ViY2x1c3RlciBpZGVudGl0aWVzCgpVc2luZyB0aGUgaW5mb3JtYXRpb24gZnJvbSBTaW5nbGVSIGFuZCBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiwgYXNzaWduIGFubm90YXRpb25zIHRvIHRoZSBzdWJjbHVzdGVycy4KCmBgYHtyIEJyZW5hbWVpZGVudHN9CkJjZWxscyA8LSBSZW5hbWVJZGVudHMoQmNlbGxzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJzAnID0gIk5haXZlIEIgQ2VsbHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJzEnID0gIk1lbW9yeSBCIENlbGxzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICcyJyA9ICJQbGFzbWEgQ2VsbHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJzMnID0gIkItMWEgQ2VsbHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJzQnID0gIlBsYXNtYSBDZWxscyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnNScgPSAiUGxhc21hIENlbGxzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICc2JyA9ICJQbGFzbWEgQ2VsbHMiKQpCY2VsbHMkaGlnaGxldmVsIDwtIElkZW50cyhCY2VsbHMpCmBgYAoKIyMjIEZpbmFsIERpbSBQbG90CgpBcyBhIGZpbmFsIGNoZWNrLCB0YWtlIGEgbG9vayBhdCB0aGUgRGltIFBsb3QgZm9yIHRoZSBzdWJjbHVzdGVycyBhbmQgY29uZmlybSB0aGF0IGl0IG1ha2VzIHNlbnNlLgoKYGBge3IgQnBsb3QsIGZpZy53aWR0aD02LCBmaWcuaGVpZ2h0PTZ9CkRpbVBsb3QoQmNlbGxzLCByZWR1Y3Rpb249InVtYXAiLCBncm91cC5ieT0iaGlnaGxldmVsIiwgbGFiZWw9VFJVRSwgcmVwZWw9VFJVRSkgKyBOb0xlZ2VuZCgpICsgbGFicyh0aXRsZT0iQiBhbmQgUGxhc21hIENlbGxzIikKYGBgCgoKCiMjIElMQ3MKCiMjIyBQQ0EgYW5kIGNsdXN0ZXJpbmcKClJ1biBQQ0EgYW5kIGRldGVybWluZSBkaW1lbnNpb25zIGZvciBjbHVzdGVyaW5nLgoKYGBge3IgSUxDUENBLCBmaWcud2lkdGg9MywgZmlnLmhlaWdodD0zfQpJTENzIDwtIHN1YnNldChkYXRhLmludGVncmF0ZWQsIGlkZW50cyA9IGMoIklMQ3MiKSkKSUxDcyA8LSBSdW5QQ0EoSUxDcywgZmVhdHVyZXM9VmFyaWFibGVGZWF0dXJlcyhJTENzKSxkaW1zPTE6MzAsIHZlcmJvc2U9RkFMU0UpCkVsYm93UGxvdChJTENzLCBuZGltcz0zMCwgcmVkdWN0aW9uPSJwY2EiKQpgYGAKCkdlbmVyYXRlIGEgY2x1c3RlcmluZyB0cmVlIGFuZCBkZXRlcm1pbmUgY2x1c3RlcmluZyByZXNvbHV0aW9uIGZvciBzdWJjbHVzdGVycy4KCmBgYHtyIElMQ2NsdXN0cmVlLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9MTJ9CklMQ3MgPC0gRmluZE5laWdoYm9ycyhJTENzLCBkaW1zPTE6MTAsIHZlcmJvc2U9RkFMU0UpIApJTENzIDwtIEZpbmRDbHVzdGVycyhJTENzLCByZXNvbHV0aW9uPXJlcywgdmVyYm9zZT1GQUxTRSkgCgojIENsdXN0ZXJpbmcgVHJlZQpjbHVzdHJlZShJTENzLCBwcmVmaXg9ImludGVncmF0ZWRfc25uX3Jlcy4iKSAKCiMgQ2hvb3NlIHJlc29sdXRpb24KSUxDcyA8LSBGaW5kQ2x1c3RlcnMoSUxDcywgcmVzb2x1dGlvbj0wLjMsIHZlcmJvc2U9RkFMU0UpIApgYGAKCiMjIyBEaW1lbnNpb25hbCBSZWR1Y3Rpb24KClBsb3QgdGhlIGRpbWVuc2lvbmFsIHJlZHVjdGlvbiBmb3IgdGhlIG5ldyBjZWxsIHN1YmNsdXN0ZXJzLgoKYGBge3IgSUxDZHIsIGZpZy53aWR0aD02LCBmaWcuaGVpZ2h0PTZ9CiMgUnVuIFVNQVAKSUxDcyA8LSBSdW5VTUFQKElMQ3MsIGRpbXM9MToxMCwgdmVyYm9zZT1GQUxTRSkgCgojIFBsb3QgVU1BUApEaW1QbG90KElMQ3MsIHJlZHVjdGlvbj0idW1hcCIsIGxhYmVsPVRSVUUpICsgTm9MZWdlbmQoKSAKYGBgCgojIyMgRmluZCBTdWJjbHVzdGVyIE1hcmtlcnMKCkZpbmQgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkIG1hcmtlcnMgYmV0d2VlbiB0aGUgc3ViY2x1c3RlcnMuCgpgYGB7ciBJTENmaW5kbWFya2Vyc30KIyBGaW5kIE1hcmtlcnMKSUxDcy5tYXJrZXJzIDwtIEZpbmRBbGxNYXJrZXJzKElMQ3MsIG9ubHkucG9zID0gVFJVRSwgbWluLnBjdCA9IDAuNTAsIGxvZ2ZjLnRocmVzaG9sZCA9IDAuMjUsIG1heC5jZWxscy5wZXIuaWRlbnQ9NTAwLCB2ZXJib3NlPUZBTFNFKSAKCiMgTGlzdCB0b3AgMTAgZ2VuZXMgZm9yIGVhY2ggc3ViY2x1c3RlciBpbiBhIHRhYmxlCklMQ3MubWFya2Vycy50b3AxMCA8LSBJTENzLm1hcmtlcnMgJT4lIGdyb3VwX2J5KGNsdXN0ZXIpICU+JSB0b3BfbihuID0gMTAsIHd0ID0gYXZnX2xvZzJGQykKSUxDcy5tYXJrZXJzLnRvcDEwICU+JSBmb3JtYXR0YWJsZSgpCmBgYAoKIyMjIFJlbmFtZSBzdWJjbHVzdGVyIGlkZW50aXRpZXMKClVzaW5nIHRoZSBpbmZvcm1hdGlvbiBmcm9tIFNpbmdsZVIgYW5kIGRpZmZlcmVudGlhbCBleHByZXNzaW9uLCBhc3NpZ24gYW5ub3RhdGlvbnMgdG8gdGhlIHN1YmNsdXN0ZXJzLgoKVGhlcmUgYXJlIG5vdCBtYW55IHNpZ25pZmljYW50IGRpZmZlcmVuY2VzIGJldHdlZW4gdGhlIHR3byBJTEMgY2x1c3RlcnMuIEluc3RlYWQsIHdlIGRlZmluZSB0aGVzZSBjZWxscyBiYXNlZCBvbiBleHByZXNzaW9uIG9mIHRoZWlyIHRyYW5zY3JpcHRpb24gZmFjdG9yIGV4cHJlc3Npb24gZm9yIEdhdGEzIGFuZCBLbHJnMS4KCmBgYHtyIElMQ3NSaWRnZSwgZmlnLndpZHRoPTksIGZpZy5oZWlnaHQ9M30KUmlkZ2VQbG90KElMQ3MsIGZlYXR1cmVzPWMoIkdhdGEzIiwiRW9tZXMiLCJSb3JjIiksIGFzc2F5PSJSTkEiKQpgYGAKCgpgYGB7ciBJTENyZW5hbWVpZGVudHN9CklMQ3MgPC0gUmVuYW1lSWRlbnRzKElMQ3MsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnMCcgPSAiSUxDMnMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJzEnID0gIklMQzJzIikKSUxDcyRoaWdobGV2ZWwgPC0gSWRlbnRzKElMQ3MpCmBgYAoKIyMjIEZpbmFsIERpbSBQbG90CgpBcyBhIGZpbmFsIGNoZWNrLCB0YWtlIGEgbG9vayBhdCB0aGUgRGltIFBsb3QgZm9yIHRoZSBzdWJjbHVzdGVycyBhbmQgY29uZmlybSB0aGF0IGl0IG1ha2VzIHNlbnNlLgoKYGBge3IgSUxDcGxvdCwgZmlnLndpZHRoPTYsIGZpZy5oZWlnaHQ9Nn0KRGltUGxvdChJTENzLCByZWR1Y3Rpb249InVtYXAiLCBncm91cC5ieT0iaGlnaGxldmVsIiwgbGFiZWw9VFJVRSkgKyBOb0xlZ2VuZCgpICsgbGFicyh0aXRsZT0iVHlwZSAyIElubmF0ZSBMeW1waG9jeXRlcyIpCmBgYAoKCgojIyBNYWNyb3BoYWdlcyBhbmQgTW9ub2N5dGVzCgojIyMgUENBIGFuZCBjbHVzdGVyaW5nCgpSdW4gUENBIGFuZCBkZXRlcm1pbmUgZGltZW5zaW9ucyBmb3IgY2x1c3RlcmluZy4KCmBgYHtyIE1NUENBLCBmaWcud2lkdGg9MywgZmlnLmhlaWdodD0zfQpNTSA8LSBzdWJzZXQoZGF0YS5pbnRlZ3JhdGVkLCBpZGVudHMgPSBjKCJNYWNyb3BoYWdlcyIsIk1vbm9jeXRlcyIpKQpNTSA8LSBSdW5QQ0EoTU0sIGZlYXR1cmVzPVZhcmlhYmxlRmVhdHVyZXMoTU0pLGRpbXM9MTozMCwgdmVyYm9zZT1GQUxTRSkKRWxib3dQbG90KE1NLCBuZGltcz0zMCwgcmVkdWN0aW9uPSJwY2EiKQpgYGAKCkdlbmVyYXRlIGEgY2x1c3RlcmluZyB0cmVlIGFuZCBkZXRlcm1pbmUgY2x1c3RlcmluZyByZXNvbHV0aW9uIGZvciBzdWJjbHVzdGVycy4KCmBgYHtyIE1NY2x1c3RyZWUsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD0xMn0KTU0gPC0gRmluZE5laWdoYm9ycyhNTSwgZGltcz0xOjI1LCB2ZXJib3NlPUZBTFNFKSAKTU0gPC0gRmluZENsdXN0ZXJzKE1NLCByZXNvbHV0aW9uPXJlcywgdmVyYm9zZT1GQUxTRSkgCgojIENsdXN0ZXJpbmcgVHJlZQpjbHVzdHJlZShNTSwgcHJlZml4PSJpbnRlZ3JhdGVkX3Nubl9yZXMuIikgCgojIENob29zZSByZXNvbHV0aW9uCk1NIDwtIEZpbmRDbHVzdGVycyhNTSwgcmVzb2x1dGlvbj0wLjI1LCB2ZXJib3NlPUZBTFNFKSAKYGBgCgojIyMgRGltZW5zaW9uYWwgUmVkdWN0aW9uCgpQbG90IHRoZSBkaW1lbnNpb25hbCByZWR1Y3Rpb24gZm9yIHRoZSBuZXcgY2VsbCBzdWJjbHVzdGVycy4KCmBgYHtyIE1NZHIsIGZpZy53aWR0aD02LCBmaWcuaGVpZ2h0PTZ9CiMgUnVuIFVNQVAKTU0gPC0gUnVuVU1BUChNTSwgZGltcz0xOjI1LCB2ZXJib3NlPUZBTFNFKSAKCiMgUGxvdCBVTUFQCkRpbVBsb3QoTU0sIHJlZHVjdGlvbj0idW1hcCIsIGxhYmVsPVRSVUUpICsgTm9MZWdlbmQoKSAKYGBgCgojIyMgRmluZCBTdWJjbHVzdGVyIE1hcmtlcnMKCkZpbmQgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkIG1hcmtlcnMgYmV0d2VlbiB0aGUgc3ViY2x1c3RlcnMuCgpgYGB7ciBNTWZpbmRtYXJrZXJzfQojIEZpbmQgTWFya2VycwpNTS5tYXJrZXJzIDwtIEZpbmRBbGxNYXJrZXJzKE1NLCBvbmx5LnBvcyA9IFRSVUUsIG1pbi5wY3QgPSAwLjUwLCBsb2dmYy50aHJlc2hvbGQgPSAwLjI1LCBtYXguY2VsbHMucGVyLmlkZW50PTUwMCwgdmVyYm9zZT1GQUxTRSkgCgojIExpc3QgdG9wIDEwIGdlbmVzIGZvciBlYWNoIHN1YmNsdXN0ZXIgaW4gYSB0YWJsZQpNTS5tYXJrZXJzLnRvcDEwIDwtIE1NLm1hcmtlcnMgJT4lIGdyb3VwX2J5KGNsdXN0ZXIpICU+JSB0b3BfbihuID0gMTAsIHd0ID0gYXZnX2xvZzJGQykKTU0ubWFya2Vycy50b3AxMCAlPiUgZm9ybWF0dGFibGUoKQpgYGAKCiMjIyBSZW5hbWUgc3ViY2x1c3RlciBpZGVudGl0aWVzCgpVc2luZyB0aGUgaW5mb3JtYXRpb24gZnJvbSBTaW5nbGVSIGFuZCBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiwgYXNzaWduIGFubm90YXRpb25zIHRvIHRoZSBzdWJjbHVzdGVycy4KCk1hY3JvcGhhZ2VzIHdlcmUgYnkgZmFyIHRoZSBsYXJnZXN0IHBvcHVsYXRpb24gYW5kIHNvbWUgb3RoZXIgY2VsbCB0eXBlcyBzZWVtIHRvIGhhdmUgc251Y2sgaW4gYnkgTG91dmFpbiBjbHVzdGVyaW5nLiBUaGUgaGlnaCBsZXZlbHMgb2YgbG9jYWwgbGlwaWQgbWF5IGluZHVjZSB0cmFuc2NyaXB0aW9uYWwgcHJvZmlsZXMgdGhhdCBjYXVzZSBkaWZmZXJlbnQgY2VsbCB0eXBlcyB0byBjb252ZXJnZS4gRm9yIGV4YW1wbGUsIHBvcHVsYXRpb24gNiBhcmUgTWFzdCBDZWxscyB1bmlxdWUgdG8gV0MgZXhwcmVzc2luZyBoaWdoIGxldmVscyBvZiBNY3B0NCBhbmQgQ21hMSwgYnV0IHRoZXkgY2FuIGJlIGZvdW5kIG5lYXIgdGhlIGxpcGlkLWFzc29jaWF0ZWQgcG9wdWxhdGlvbi4KCgpgYGB7ciBNTXJlbmFtZWlkZW50c30KTU0gPC0gUmVuYW1lSWRlbnRzKE1NLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJzAnID0gIlRpc3N1ZSBSZXNpZGVudCBNYWNyb3BoYWdlcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnMScgPSAiVGlzc3VlIFJlc2lkZW50IE1hY3JvcGhhZ2VzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICcyJyA9ICJDbGFzc2ljYWwgTW9ub2N5dGVzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICczJyA9ICJMQU1zIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICc0JyA9ICJMQU1zIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICc1JyA9ICJOb24tY2xhc3NpY2FsIE1vbm9jeXRlcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnNicgPSAiUHJvbGlmZXJhdGluZyBNYWNyb3BoYWdlcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnNycgPSAiTWFzdCBDZWxscyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnOCcgPSAiTEFNcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnOScgPSAiQXBvcHRvdGljIENlbGwgQ2xlYXJhbmNlIE1hY3JvcGhhZ2VzIikKTU0kaGlnaGxldmVsIDwtIElkZW50cyhNTSkKYGBgCgojIyMgRmluYWwgRGltIFBsb3QKCkFzIGEgZmluYWwgY2hlY2ssIHRha2UgYSBsb29rIGF0IHRoZSBEaW0gUGxvdCBmb3IgdGhlIHN1YmNsdXN0ZXJzIGFuZCBjb25maXJtIHRoYXQgaXQgbWFrZXMgc2Vuc2UuCgpgYGB7ciBNTXBsb3QsIGZpZy53aWR0aD02LCBmaWcuaGVpZ2h0PTZ9CkRpbVBsb3QoTU0sIHJlZHVjdGlvbj0idW1hcCIsIGdyb3VwLmJ5PSJoaWdobGV2ZWwiLCBsYWJlbD1UUlVFLCByZXBlbD1UUlVFKSArIE5vTGVnZW5kKCkgKyBsYWJzKHRpdGxlPSJNb25vY3l0ZXMgYW5kIE1hY3JvcGhhZ2VzIikKYGBgCgoKCiMjIFN0cm9tYWwgQ2VsbHMKCiMjIyBQQ0EgYW5kIGNsdXN0ZXJpbmcKClJ1biBQQ0EgYW5kIGRldGVybWluZSBkaW1lbnNpb25zIGZvciBjbHVzdGVyaW5nLgoKYGBge3Igc3Ryb21hbFBDQSwgZmlnLndpZHRoPTMsIGZpZy5oZWlnaHQ9M30KU3Ryb21hbCA8LSBzdWJzZXQoZGF0YS5pbnRlZ3JhdGVkLCBpZGVudHMgPSBjKCJTdHJvbWFsIENlbGxzIikpClN0cm9tYWwgPC0gUnVuUENBKFN0cm9tYWwsIGZlYXR1cmVzPVZhcmlhYmxlRmVhdHVyZXMoU3Ryb21hbCksZGltcz0xOjMwLCB2ZXJib3NlPUZBTFNFKQpFbGJvd1Bsb3QoU3Ryb21hbCwgbmRpbXM9MzAsIHJlZHVjdGlvbj0icGNhIikKYGBgCgpHZW5lcmF0ZSBhIGNsdXN0ZXJpbmcgdHJlZSBhbmQgZGV0ZXJtaW5lIGNsdXN0ZXJpbmcgcmVzb2x1dGlvbiBmb3Igc3ViY2x1c3RlcnMuCgpgYGB7ciBzdHJvbWFsY2x1c3RyZWUsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD0xMn0KU3Ryb21hbCA8LSBGaW5kTmVpZ2hib3JzKFN0cm9tYWwsIGRpbXM9MToxMCwgdmVyYm9zZT1GQUxTRSkgClN0cm9tYWwgPC0gRmluZENsdXN0ZXJzKFN0cm9tYWwsIHJlc29sdXRpb249cmVzLCB2ZXJib3NlPUZBTFNFKSAKCiMgQ2x1c3RlcmluZyBUcmVlCmNsdXN0cmVlKFN0cm9tYWwsIHByZWZpeD0iaW50ZWdyYXRlZF9zbm5fcmVzLiIpIAoKIyBDaG9vc2UgcmVzb2x1dGlvbgpTdHJvbWFsIDwtIEZpbmRDbHVzdGVycyhTdHJvbWFsLCByZXNvbHV0aW9uPTAuMiwgdmVyYm9zZT1GQUxTRSkgCmBgYAoKIyMjIERpbWVuc2lvbmFsIFJlZHVjdGlvbgoKUGxvdCB0aGUgZGltZW5zaW9uYWwgcmVkdWN0aW9uIGZvciB0aGUgbmV3IGNlbGwgc3ViY2x1c3RlcnMuCgpgYGB7ciBzdHJvbWFsZHIsIGZpZy53aWR0aD02LCBmaWcuaGVpZ2h0PTZ9CiMgUnVuIFVNQVAKU3Ryb21hbCA8LSBSdW5VTUFQKFN0cm9tYWwsIGRpbXM9MToxMCwgdmVyYm9zZT1GQUxTRSkgCgojIFBsb3QgVU1BUApEaW1QbG90KFN0cm9tYWwsIHJlZHVjdGlvbj0idW1hcCIsIGxhYmVsPVRSVUUpICsgTm9MZWdlbmQoKSAKYGBgCgojIyMgRmluZCBTdWJjbHVzdGVyIE1hcmtlcnMKCkZpbmQgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkIG1hcmtlcnMgYmV0d2VlbiB0aGUgc3ViY2x1c3RlcnMuCgpgYGB7ciBzdHJvbWFsZmluZG1hcmtlcnN9CiMgRmluZCBNYXJrZXJzClN0cm9tYWwubWFya2VycyA8LSBGaW5kQWxsTWFya2VycyhTdHJvbWFsLCBvbmx5LnBvcyA9IFRSVUUsIG1pbi5wY3QgPSAwLjUwLCBsb2dmYy50aHJlc2hvbGQgPSAwLjI1LCBtYXguY2VsbHMucGVyLmlkZW50PTUwMCwgdmVyYm9zZT1GQUxTRSkgCgojIExpc3QgdG9wIDEwIGdlbmVzIGZvciBlYWNoIHN1YmNsdXN0ZXIgaW4gYSB0YWJsZQpTdHJvbWFsLm1hcmtlcnMudG9wMTAgPC0gU3Ryb21hbC5tYXJrZXJzICU+JSBncm91cF9ieShjbHVzdGVyKSAlPiUgdG9wX24obiA9IDEwLCB3dCA9IGF2Z19sb2cyRkMpClN0cm9tYWwubWFya2Vycy50b3AxMCAlPiUgZm9ybWF0dGFibGUoKQpgYGAKCiMjIyBSZW5hbWUgc3ViY2x1c3RlciBpZGVudGl0aWVzCgpVc2luZyB0aGUgaW5mb3JtYXRpb24gZnJvbSBTaW5nbGVSIGFuZCBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiwgYXNzaWduIGFubm90YXRpb25zIHRvIHRoZSBzdWJjbHVzdGVycy4KCmBgYHtyIHN0cm9tYWxyZW5hbWVpZGVudHN9ClN0cm9tYWwgPC0gUmVuYW1lSWRlbnRzKFN0cm9tYWwsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnMCcgPSAiQWRpcG9jeXRlIFByZWN1cnNvciBDZWxscyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnMScgPSAiQWRpcG9jeXRlIFByZWN1cnNvciBDZWxscyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnMicgPSAiQWRpcG9jeXRlIFByZWN1cnNvciBDZWxscyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnMycgPSAiQWRpcG9jeXRlIFByZWN1cnNvciBDZWxscyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnNCcgPSAiQWRpcG9jeXRlIFByZWN1cnNvciBDZWxscyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnNScgPSAiTWVzb3RoZWxpYWwtbGlrZSBDZWxscyIpClN0cm9tYWwkaGlnaGxldmVsIDwtIElkZW50cyhTdHJvbWFsKQpgYGAKCiMjIyBGaW5hbCBEaW0gUGxvdAoKQXMgYSBmaW5hbCBjaGVjaywgdGFrZSBhIGxvb2sgYXQgdGhlIERpbSBQbG90IGZvciB0aGUgc3ViY2x1c3RlcnMgYW5kIGNvbmZpcm0gdGhhdCBpdCBtYWtlcyBzZW5zZS4KCmBgYHtyIHN0cm9tYWxwbG90LCBmaWcud2lkdGg9NiwgZmlnLmhlaWdodD02fQpEaW1QbG90KFN0cm9tYWwsIHJlZHVjdGlvbj0idW1hcCIsIGdyb3VwLmJ5PSJoaWdobGV2ZWwiLCBsYWJlbD1UUlVFLCByZXBlbD1UUlVFKSArIE5vTGVnZW5kKCkgKyBsYWJzKHRpdGxlPSJTdHJvbWFsIENlbGxzIikKYGBgCgoKCgoKIyMgTWFzdCBDZWxscwoKIyMjIFBDQSBhbmQgY2x1c3RlcmluZwoKUnVuIFBDQSBhbmQgZGV0ZXJtaW5lIGRpbWVuc2lvbnMgZm9yIGNsdXN0ZXJpbmcuCgpgYGB7ciBtYXN0UENBLCBmaWcud2lkdGg9MywgZmlnLmhlaWdodD0zfQpNYXN0IDwtIHN1YnNldChkYXRhLmludGVncmF0ZWQsIGlkZW50cyA9IGMoIk1hc3QgQ2VsbHMiKSkKTWFzdCA8LSBSdW5QQ0EoTWFzdCwgZmVhdHVyZXM9VmFyaWFibGVGZWF0dXJlcyhNYXN0KSxkaW1zPTE6MzAsIHZlcmJvc2U9RkFMU0UpCkVsYm93UGxvdChNYXN0LCBuZGltcz0zMCwgcmVkdWN0aW9uPSJwY2EiKQpgYGAKCkdlbmVyYXRlIGEgY2x1c3RlcmluZyB0cmVlIGFuZCBkZXRlcm1pbmUgY2x1c3RlcmluZyByZXNvbHV0aW9uIGZvciBzdWJjbHVzdGVycy4KCmBgYHtyIG1hc3RjbHVzdHJlZSwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTEyfQpNYXN0IDwtIEZpbmROZWlnaGJvcnMoTWFzdCwgZGltcz0xOjEwLCB2ZXJib3NlPUZBTFNFKSAKTWFzdCA8LSBGaW5kQ2x1c3RlcnMoTWFzdCwgcmVzb2x1dGlvbj1yZXMsIHZlcmJvc2U9RkFMU0UpIAoKIyBDbHVzdGVyaW5nIFRyZWUKY2x1c3RyZWUoTWFzdCwgcHJlZml4PSJpbnRlZ3JhdGVkX3Nubl9yZXMuIikgCgojIENob29zZSByZXNvbHV0aW9uCk1hc3QgPC0gRmluZENsdXN0ZXJzKE1hc3QsIHJlc29sdXRpb249MC4yLCB2ZXJib3NlPUZBTFNFKSAKYGBgCgojIyMgRGltZW5zaW9uYWwgUmVkdWN0aW9uCgpQbG90IHRoZSBkaW1lbnNpb25hbCByZWR1Y3Rpb24gZm9yIHRoZSBuZXcgY2VsbCBzdWJjbHVzdGVycy4KCmBgYHtyIG1hc3RkciwgZmlnLndpZHRoPTYsIGZpZy5oZWlnaHQ9Nn0KIyBSdW4gVU1BUApNYXN0IDwtIFJ1blVNQVAoTWFzdCwgZGltcz0xOjEwLCB2ZXJib3NlPUZBTFNFKSAKCiMgUGxvdCBVTUFQCkRpbVBsb3QoTWFzdCwgcmVkdWN0aW9uPSJ1bWFwIiwgbGFiZWw9VFJVRSkgKyBOb0xlZ2VuZCgpIApgYGAKCiMjIyBSZW5hbWUgc3ViY2x1c3RlciBpZGVudGl0aWVzCgpVc2luZyB0aGUgaW5mb3JtYXRpb24gZnJvbSBTaW5nbGVSIGFuZCBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiwgYXNzaWduIGFubm90YXRpb25zIHRvIHRoZSBzdWJjbHVzdGVycy4KCmBgYHtyIG1hc3RyZW5hbWVpZGVudHN9Ck1hc3QgPC0gUmVuYW1lSWRlbnRzKE1hc3QsIAogICAgICAgICAgICAgICAgICAgICAnMCcgPSAiTWFzdCBDZWxscyIsCiAgICAgICAgICAgICAgICAgICAgICcxJyA9ICJNYXN0IENlbGxzIikKTWFzdCRoaWdobGV2ZWwgPC0gSWRlbnRzKE1hc3QpCmBgYAoKIyMjIEZpbmFsIERpbSBQbG90CgpBcyBhIGZpbmFsIGNoZWNrLCB0YWtlIGEgbG9vayBhdCB0aGUgRGltIFBsb3QgZm9yIHRoZSBzdWJjbHVzdGVycyBhbmQgY29uZmlybSB0aGF0IGl0IG1ha2VzIHNlbnNlLgoKYGBge3IgbWFzdHBsb3QsIGZpZy53aWR0aD02LCBmaWcuaGVpZ2h0PTZ9CkRpbVBsb3QoTWFzdCwgcmVkdWN0aW9uPSJ1bWFwIiwgZ3JvdXAuYnk9ImhpZ2hsZXZlbCIsIGxhYmVsPVRSVUUsIHJlcGVsPVRSVUUpICsgTm9MZWdlbmQoKSArIGxhYnModGl0bGU9Ik1hc3QgQ2VsbHMiKQpgYGAKCgoKCgojIyBOZXV0cm9waGlscwoKIyMjIFBDQSBhbmQgY2x1c3RlcmluZwoKUnVuIFBDQSBhbmQgZGV0ZXJtaW5lIGRpbWVuc2lvbnMgZm9yIGNsdXN0ZXJpbmcuCgpgYGB7ciBuZXV0cm9QQ0EsIGZpZy53aWR0aD0zLCBmaWcuaGVpZ2h0PTN9Ck5ldXRyb3BoaWxzIDwtIHN1YnNldChkYXRhLmludGVncmF0ZWQsIGlkZW50cyA9IGMoIk5ldXRyb3BoaWxzIikpCk5ldXRyb3BoaWxzIDwtIFJ1blBDQShOZXV0cm9waGlscywgZmVhdHVyZXM9VmFyaWFibGVGZWF0dXJlcyhOZXV0cm9waGlscyksZGltcz0xOjMwLCB2ZXJib3NlPUZBTFNFKQpFbGJvd1Bsb3QoTmV1dHJvcGhpbHMsIG5kaW1zPTMwLCByZWR1Y3Rpb249InBjYSIpCmBgYAoKR2VuZXJhdGUgYSBjbHVzdGVyaW5nIHRyZWUgYW5kIGRldGVybWluZSBjbHVzdGVyaW5nIHJlc29sdXRpb24gZm9yIHN1YmNsdXN0ZXJzLgoKYGBge3IgbmV1dHJvY2x1c3RyZWUsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD0xMn0KTmV1dHJvcGhpbHMgPC0gRmluZE5laWdoYm9ycyhOZXV0cm9waGlscywgZGltcz0xOjEwLCB2ZXJib3NlPUZBTFNFKSAKTmV1dHJvcGhpbHMgPC0gRmluZENsdXN0ZXJzKE5ldXRyb3BoaWxzLCByZXNvbHV0aW9uPXJlcywgdmVyYm9zZT1GQUxTRSkgCgojIENsdXN0ZXJpbmcgVHJlZQpjbHVzdHJlZShOZXV0cm9waGlscywgcHJlZml4PSJpbnRlZ3JhdGVkX3Nubl9yZXMuIikgCgojIENob29zZSByZXNvbHV0aW9uCk5ldXRyb3BoaWxzIDwtIEZpbmRDbHVzdGVycyhOZXV0cm9waGlscywgcmVzb2x1dGlvbj0wLjIsIHZlcmJvc2U9RkFMU0UpIApgYGAKCiMjIyBEaW1lbnNpb25hbCBSZWR1Y3Rpb24KClBsb3QgdGhlIGRpbWVuc2lvbmFsIHJlZHVjdGlvbiBmb3IgdGhlIG5ldyBjZWxsIHN1YmNsdXN0ZXJzLgoKYGBge3IgbmV1dHJvZHIsIGZpZy53aWR0aD02LCBmaWcuaGVpZ2h0PTZ9CiMgUnVuIFVNQVAKTmV1dHJvcGhpbHMgPC0gUnVuVU1BUChOZXV0cm9waGlscywgZGltcz0xOjEwLCB2ZXJib3NlPUZBTFNFKSAKCiMgUGxvdCBVTUFQCkRpbVBsb3QoTmV1dHJvcGhpbHMsIHJlZHVjdGlvbj0idW1hcCIsIGxhYmVsPVRSVUUpICsgTm9MZWdlbmQoKSAKYGBgCgojIyMgUmVuYW1lIHN1YmNsdXN0ZXIgaWRlbnRpdGllcwoKVXNpbmcgdGhlIGluZm9ybWF0aW9uIGZyb20gU2luZ2xlUiBhbmQgZGlmZmVyZW50aWFsIGV4cHJlc3Npb24sIGFzc2lnbiBhbm5vdGF0aW9ucyB0byB0aGUgc3ViY2x1c3RlcnMuCgpgYGB7ciBuZXV0cm9uYW1laWRlbnRzfQpOZXV0cm9waGlscyA8LSBSZW5hbWVJZGVudHMoTmV1dHJvcGhpbHMsICcwJyA9ICJOZXV0cm9waGlscyIpCk5ldXRyb3BoaWxzJGhpZ2hsZXZlbCA8LSBJZGVudHMoTmV1dHJvcGhpbHMpCmBgYAoKIyMjIEZpbmFsIERpbSBQbG90CgpBcyBhIGZpbmFsIGNoZWNrLCB0YWtlIGEgbG9vayBhdCB0aGUgRGltIFBsb3QgZm9yIHRoZSBzdWJjbHVzdGVycyBhbmQgY29uZmlybSB0aGF0IGl0IG1ha2VzIHNlbnNlLgoKYGBge3IgbmV1dHJvcGxvdCwgZmlnLndpZHRoPTYsIGZpZy5oZWlnaHQ9Nn0KRGltUGxvdChOZXV0cm9waGlscywgcmVkdWN0aW9uPSJ1bWFwIiwgZ3JvdXAuYnk9ImhpZ2hsZXZlbCIsIGxhYmVsPVRSVUUsIHJlcGVsPVRSVUUpICsgTm9MZWdlbmQoKSArIGxhYnModGl0bGU9Ik5ldXRyb3BoaWxzIikKYGBgCgoKCgoKIyMgRW5kb3RoZWxpYWwgQ2VsbHMKCiMjIyBQQ0EgYW5kIGNsdXN0ZXJpbmcKClJ1biBQQ0EgYW5kIGRldGVybWluZSBkaW1lbnNpb25zIGZvciBjbHVzdGVyaW5nLgoKYGBge3IgZW5kb1BDQSwgZmlnLndpZHRoPTMsIGZpZy5oZWlnaHQ9M30KRUNzIDwtIHN1YnNldChkYXRhLmludGVncmF0ZWQsIGlkZW50cyA9IGMoIkVuZG90aGVsaWFsIENlbGxzIikpCkVDcyA8LSBSdW5QQ0EoRUNzLCBmZWF0dXJlcz1WYXJpYWJsZUZlYXR1cmVzKEVDcyksZGltcz0xOjMwLCB2ZXJib3NlPUZBTFNFKQpFbGJvd1Bsb3QoRUNzLCBuZGltcz0zMCwgcmVkdWN0aW9uPSJwY2EiKQpgYGAKCkdlbmVyYXRlIGEgY2x1c3RlcmluZyB0cmVlIGFuZCBkZXRlcm1pbmUgY2x1c3RlcmluZyByZXNvbHV0aW9uIGZvciBzdWJjbHVzdGVycy4KCmBgYHtyIGVuZG9jbHVzdHJlZSwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTEyfQpFQ3MgPC0gRmluZE5laWdoYm9ycyhFQ3MsIGRpbXM9MToxMCwgdmVyYm9zZT1GQUxTRSkgCkVDcyA8LSBGaW5kQ2x1c3RlcnMoRUNzLCByZXNvbHV0aW9uPXJlcywgdmVyYm9zZT1GQUxTRSkgCgojIENsdXN0ZXJpbmcgVHJlZQpjbHVzdHJlZShFQ3MsIHByZWZpeD0iaW50ZWdyYXRlZF9zbm5fcmVzLiIpIAoKIyBDaG9vc2UgcmVzb2x1dGlvbgpFQ3MgPC0gRmluZENsdXN0ZXJzKEVDcywgcmVzb2x1dGlvbj0wLjMsIHZlcmJvc2U9RkFMU0UpIApgYGAKCiMjIyBEaW1lbnNpb25hbCBSZWR1Y3Rpb24KClBsb3QgdGhlIGRpbWVuc2lvbmFsIHJlZHVjdGlvbiBmb3IgdGhlIG5ldyBjZWxsIHN1YmNsdXN0ZXJzLgoKYGBge3IgZW5kb2RyLCBmaWcud2lkdGg9NiwgZmlnLmhlaWdodD02fQojIFJ1biBVTUFQCkVDcyA8LSBSdW5VTUFQKEVDcywgZGltcz0xOjEwLCB2ZXJib3NlPUZBTFNFKSAKCiMgUGxvdCBVTUFQCkRpbVBsb3QoRUNzLCByZWR1Y3Rpb249InVtYXAiLCBsYWJlbD1UUlVFKSArIE5vTGVnZW5kKCkgCmBgYAoKIyMjIFJlbmFtZSBzdWJjbHVzdGVyIGlkZW50aXRpZXMKClVzaW5nIHRoZSBpbmZvcm1hdGlvbiBmcm9tIFNpbmdsZVIgYW5kIGRpZmZlcmVudGlhbCBleHByZXNzaW9uLCBhc3NpZ24gYW5ub3RhdGlvbnMgdG8gdGhlIHN1YmNsdXN0ZXJzLgoKYGBge3IgZW5kb3JlbmFtZWlkZW50c30KRUNzIDwtIFJlbmFtZUlkZW50cyhFQ3MsICcwJyA9ICJFbmRvdGhlbGlhbCBDZWxscyIpCkVDcyRoaWdobGV2ZWwgPC0gSWRlbnRzKEVDcykKYGBgCgojIyMgRmluYWwgRGltIFBsb3QKCkFzIGEgZmluYWwgY2hlY2ssIHRha2UgYSBsb29rIGF0IHRoZSBEaW0gUGxvdCBmb3IgdGhlIHN1YmNsdXN0ZXJzIGFuZCBjb25maXJtIHRoYXQgaXQgbWFrZXMgc2Vuc2UuCgpgYGB7ciBlbmRvcGxvdCwgZmlnLndpZHRoPTYsIGZpZy5oZWlnaHQ9Nn0KRGltUGxvdChFQ3MsIHJlZHVjdGlvbj0idW1hcCIsIGdyb3VwLmJ5PSJoaWdobGV2ZWwiLCBsYWJlbD1UUlVFLCByZXBlbD1UUlVFKSArIE5vTGVnZW5kKCkgKyBsYWJzKHRpdGxlPSJFbmRvdGhlbGlhbCBDZWxscyIpCmBgYAoKCgoKCiMjIFN0b3JlIHRoZSBzdWJjbHVzdGVyIGlkZW50aXRpZXMgCgpPbmNlIHdlIGhhdmUgcmVuYW1lZCBvdXIgY2VsbCBzdWJjbHVzdGVycywgd2UgaGF2ZSB0byBtZXJnZSB0aGUgc3Vic2V0dGVkIGRhdGEgYW5kIHRoZW4gYWRkIHRoaXMgaW5mb3JtYXRpb24gdG8gb3VyIG9yaWdpbmFsIGludGVncmF0ZWQgU2V1cmF0IG9iamVjdC4KCmBgYHtyIHJlbWVyZ2VpZGVudHN9CnJlbWVyZ2UgPC0gbWVyZ2UoTktULCB5PWMoRENzLCBCY2VsbHMsIElMQ3MsIE1NLCBTdHJvbWFsLCBNYXN0LCBOZXV0cm9waGlscywgRUNzKSkgCmRhdGEuaW50ZWdyYXRlZCA8LSBBZGRNZXRhRGF0YShkYXRhLmludGVncmF0ZWQsIHJlbWVyZ2UkaGlnaGxldmVsLCBjb2wubmFtZT0gImhpZ2hsZXZlbCIpCmBgYAoKIyMgQ29ycmVjdCBpZGVudGl0aWVzCgojIyMgRW5kb3RoZWxpYWwgdG8gc3Ryb21hbAoKSW4gbGF0ZXIgYW5hbHlzaXMsIHdlIHJlY2xhc3NpZmllZCBlbmRvdGhlbGlhbCBjZWxscyBhcyBwYXJ0IG9mIHRoZSBtYWpvciBzdHJvbWFsIGNlbGwgY2x1c3Rlci4gVG8gc2VwYXJhdGUgdGhlc2UgY2hhbmdlcyBmcm9tIG91ciBvcmlnaW5hbCBwcm9wcm9jZXNzaW5nLCBJIGRlc2lnbmF0ZWQgdGhlc2UgaWRlbnRpdGllcyBhcyBgbG93bGV2ZWwyYAoKYGBge3IgZW5kb3Rvc3Ryb21hbH0KSWRlbnRzKGRhdGEuaW50ZWdyYXRlZCkgPC0gZGF0YS5pbnRlZ3JhdGVkJGxvd2xldmVsCmRhdGEuaW50ZWdyYXRlZCA8LSBSZW5hbWVJZGVudHMoZGF0YS5pbnRlZ3JhdGVkLCAiRW5kb3RoZWxpYWwgQ2VsbHMiID0gIlN0cm9tYWwgQ2VsbHMiKQpkYXRhLmludGVncmF0ZWQkbG93bGV2ZWwyIDwtIElkZW50cyhkYXRhLmludGVncmF0ZWQpCmRhdGEuaW50ZWdyYXRlZCRsb3dsZXZlbDIgPC0gZmFjdG9yKGRhdGEuaW50ZWdyYXRlZCRsb3dsZXZlbDIsIGxldmVscz1jKCJNYWNyb3BoYWdlcyIsIk1vbm9jeXRlcyIsIkRlbmRyaXRpYyBDZWxscyIsIlQgQ2VsbHMiLCJOSyBDZWxscyIsIkIgQ2VsbHMiLCJQbGFzbWEgQ2VsbHMiLCJNYXN0IENlbGxzIiwiTmV1dHJvcGhpbHMiLCJJTENzIiwiU3Ryb21hbCBDZWxscyIpKQpgYGAKCiMjIyBBZGp1c3QgaGlnaGxldmVsIHN1YmNsdXN0ZXJzCgpXZSBhbHNvIHJlbmFtZWQgc29tZSBvZiB0aGUgc3ViY2x1c3RlcnMgdG8gY2xhcmlmeSB3aGF0IHRoZXNlIGNlbGwgdHlwZXMgYXJlLiBBZ2Fpbiwgd2UgZ2F2ZSB0aGVzZSByZW5hbWVkIGNsdXN0ZXJzIHRoZWlyIG93biBkZXNpZ25hdGlvbiB0byBhdm9pZCBjb25mdXNpb24gd2l0aCBvdXIgcHJlcHJvY2Vzc2luZyBwaXBlbGluZSBhbmQgY2FsbGVkIHRoZW0gYGhpZ2hsZXZlbDJgLiAKCmBgYHtyIGFkamhsfQpJZGVudHMoZGF0YS5pbnRlZ3JhdGVkKSA8LSBkYXRhLmludGVncmF0ZWQkaGlnaGxldmVsCmRhdGEuaW50ZWdyYXRlZCA8LSBSZW5hbWVJZGVudHMoZGF0YS5pbnRlZ3JhdGVkLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJBcG9wdG90aWMgQ2VsbCBDbGVhcmFuY2UgTWFjcm9waGFnZXMiID0gIkVmZmVyb2N5dGVzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiZ2QgVCBjZWxscyIgPSAiZ2QgVCBDZWxscyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlByb2xpZmVyYXRpbmcgTWFjcm9waGFnZXMiID0gIkN5Y2xpbmcgTWFjcm9waGFnZXMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJQcm9saWZlcmF0aW5nIGNEQzIiID0gIkN5Y2xpbmcgY0RDMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlByb2xpZmVyYXRpbmcgY0RDMSIgPSAiQ3ljbGluZyBjREMxIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUHJvbGlmZXJhdGluZyBDRDgrIFQgQ2VsbHMiID0gIkN5Y2xpbmcgQ0Q4KyBUIENlbGxzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRWZmZWN0b3IgQ0Q4KyBUIENlbGxzIiA9ICJFZmZlY3RvciBNZW1vcnkgQ0Q4KyBUIENlbGxzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTWVtb3J5IENEOCsgVCBDZWxscyIgPSAiQ2VudHJhbCBNZW1vcnkgQ0Q4KyBUIENlbGxzIikKZGF0YS5pbnRlZ3JhdGVkJGhpZ2hsZXZlbDIgPC0gSWRlbnRzKGRhdGEuaW50ZWdyYXRlZCkKYGBgCgojIyMgQ29ycmVjdCBsb3dsZXZlbCBhbmQgaGlnaGxldmVsIGRlc2lnbmF0aW9ucwoKRm9yIHJvYnVzdG5lc3MsIHdlIGFsc28gbWFkZSBzdXJlIHRoYXQgY2VsbHMgdGhhdCBhcmUgbWFjcm9waGFnZSBzdWJjbHVzdGVycyBzaG91bGQgYmUgdW5kZXIgdGhlIGBtYWNyb3BoYWdlYCB1bWJyZWxsYS4gVGhpcyBmaXhlcyBzb21lIHByb2JsZW1zIG5vdGVkIGFib3ZlLCBzdWNoIGFzIGEgbWFzdCBjZWxsIHBvcHVsYXRpb24gdGhhdCB3YXMgb3JpZ2luYWxseSBjbHVzdGVyZWQgaW4gd2l0aCB0aGUgbWFjcm9waGFnZXMuCgpgYGB7ciBhZGpsbH0KSWRlbnRzKGRhdGEuaW50ZWdyYXRlZCkgPC0gZGF0YS5pbnRlZ3JhdGVkJGhpZ2hsZXZlbDIKCmRhdGEuaW50ZWdyYXRlZCRsb3dsZXZlbDJbV2hpY2hDZWxscyhkYXRhLmludGVncmF0ZWQsIGlkZW50cz1jKCJUaXNzdWUgUmVzaWRlbnQgTWFjcm9waGFnZXMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTEFNcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDeWNsaW5nIE1hY3JvcGhhZ2VzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkVmZmVyb2N5dGVzIikpXSA8LSAiTWFjcm9waGFnZXMiCmRhdGEuaW50ZWdyYXRlZCRsb3dsZXZlbDJbV2hpY2hDZWxscyhkYXRhLmludGVncmF0ZWQsIGlkZW50cz1jKCJDbGFzc2ljYWwgTW9ub2N5dGVzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk5vbi1jbGFzc2ljYWwgTW9ub2N5dGVzIikpXSA8LSAiTW9ub2N5dGVzIgpkYXRhLmludGVncmF0ZWQkbG93bGV2ZWwyW1doaWNoQ2VsbHMoZGF0YS5pbnRlZ3JhdGVkLCBpZGVudHM9YygiY0RDMSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJBY3RpdmF0ZWQgY0RDMSIsIkN5Y2xpbmcgY0RDMSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjREMyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkFjdGl2YXRlZCBjREMyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkN5Y2xpbmcgY0RDMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwRENzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIm1vRENzIikpXSA8LSAiRGVuZHJpdGljIENlbGxzIgpkYXRhLmludGVncmF0ZWQkbG93bGV2ZWwyW1doaWNoQ2VsbHMoZGF0YS5pbnRlZ3JhdGVkLCBpZGVudHM9YygiVGgxIENENCsgVCBDZWxscyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJUaDIgQ0Q0KyBUIENlbGxzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlRyZWdzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkVmZmVjdG9yIE1lbW9yeSBDRDgrIFQgQ2VsbHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ2VudHJhbCBNZW1vcnkgQ0Q4KyBUIENlbGxzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkN5Y2xpbmcgQ0Q4KyBUIENlbGxzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImdkIFQgQ2VsbHMiKSldIDwtICJUIENlbGxzIgpkYXRhLmludGVncmF0ZWQkbG93bGV2ZWwyW1doaWNoQ2VsbHMoZGF0YS5pbnRlZ3JhdGVkLCBpZGVudHM9YygiTktUIENlbGxzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk5LIENlbGxzIikpXSA8LSAiTksgQ2VsbHMiCmRhdGEuaW50ZWdyYXRlZCRsb3dsZXZlbDJbV2hpY2hDZWxscyhkYXRhLmludGVncmF0ZWQsIGlkZW50cz1jKCJOYWl2ZSBCIENlbGxzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk1lbW9yeSBCIENlbGxzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkItMWEgQ2VsbHMiKSldIDwtICJCIENlbGxzIgpkYXRhLmludGVncmF0ZWQkbG93bGV2ZWwyW1doaWNoQ2VsbHMoZGF0YS5pbnRlZ3JhdGVkLCBpZGVudHM9YygiUGxhc21hIENlbGxzIikpXSA8LSAiUGxhc21hIENlbGxzIgpkYXRhLmludGVncmF0ZWQkbG93bGV2ZWwyW1doaWNoQ2VsbHMoZGF0YS5pbnRlZ3JhdGVkLCBpZGVudHM9YygiTWFzdCBDZWxscyIpKV0gPC0gIk1hc3QgQ2VsbHMiCmRhdGEuaW50ZWdyYXRlZCRsb3dsZXZlbDJbV2hpY2hDZWxscyhkYXRhLmludGVncmF0ZWQsIGlkZW50cz1jKCJOZXV0cm9waGlscyIpKV0gPC0gIk5ldXRyb3BoaWxzIgpkYXRhLmludGVncmF0ZWQkbG93bGV2ZWwyW1doaWNoQ2VsbHMoZGF0YS5pbnRlZ3JhdGVkLCBpZGVudHM9YygiSUxDMnMiKSldIDwtICJJTENzIgpkYXRhLmludGVncmF0ZWQkbG93bGV2ZWwyW1doaWNoQ2VsbHMoZGF0YS5pbnRlZ3JhdGVkLCBpZGVudHM9YygiRW5kb3RoZWxpYWwgQ2VsbHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQWRpcG9jeXRlIFByZWN1cnNvciBDZWxscyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJNZXNvdGhlbGlhbC1saWtlIENlbGxzIikpXSA8LSAiU3Ryb21hbCBDZWxscyIKYGBgCgoKIyMjIFJlb3JkZXIgdGhlIGlkZW50aXRpZXMKCkZpbmFsbHksIHdlIHJlb3JkZXIgb3VyIGlkZW50aXRpZXMsIHdoaWNoIG1ha2VzIGRvd25zdHJlYW0gcGxvdHRpbmcgbXVjaCBlYXNpZXIuCgpgYGB7ciByZW9yZGVyaWRlbnRzfQojT3JkZXIgbGV2ZWxzIG9mIGRhdGEuaW50ZWdyYXRlZApkYXRhLmludGVncmF0ZWQkaGlnaGxldmVsMiA8LSBmYWN0b3IoZGF0YS5pbnRlZ3JhdGVkJGhpZ2hsZXZlbDIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzPWMoIlRpc3N1ZSBSZXNpZGVudCBNYWNyb3BoYWdlcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTEFNcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ3ljbGluZyBNYWNyb3BoYWdlcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRWZmZXJvY3l0ZXMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNsYXNzaWNhbCBNb25vY3l0ZXMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk5vbi1jbGFzc2ljYWwgTW9ub2N5dGVzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjREMxIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJBY3RpdmF0ZWQgY0RDMSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ3ljbGluZyBjREMxIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjREMyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJBY3RpdmF0ZWQgY0RDMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ3ljbGluZyBjREMyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwRENzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJtb0RDcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVGgxIENENCsgVCBDZWxscyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVGgyIENENCsgVCBDZWxscyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVHJlZ3MiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkVmZmVjdG9yIE1lbW9yeSBDRDgrIFQgQ2VsbHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNlbnRyYWwgTWVtb3J5IENEOCsgVCBDZWxscyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ3ljbGluZyBDRDgrIFQgQ2VsbHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImdkIFQgQ2VsbHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk5LIENlbGxzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJOS1QgQ2VsbHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk5haXZlIEIgQ2VsbHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk1lbW9yeSBCIENlbGxzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJCLTFhIENlbGxzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJQbGFzbWEgQ2VsbHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk1hc3QgQ2VsbHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk5ldXRyb3BoaWxzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJJTEMycyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRW5kb3RoZWxpYWwgQ2VsbHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkFkaXBvY3l0ZSBQcmVjdXJzb3IgQ2VsbHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk1lc290aGVsaWFsLWxpa2UgQ2VsbHMiKSkKYGBgCgoKCgojIFBsb3QgQ2x1c3RlciBBbm5vdGF0aW9ucwoKIyMgQ29sb3JzCgpGaXJzdCwgYXNzaWduIHRoZSBjb2xvcnMgdGhhdCB3ZSB1c2UgdGhyb3VnaG91dCB0aGUgc3R1ZHkuCgpgYGB7ciBjb2xvcnN9Cm1hY2NvbHMgPC0gYnJld2VyLnBhbChuPTgsIG5hbWU9IkJsdWVzIilbYygtMSwtMywtNSwtNyldCm1vbm9jb2xzIDwtIGMoIiNmZjhhZGUiLCIjZTMyNGFkIikKZGNjb2xzIDwtIGJyZXdlci5wYWwobj05LCBuYW1lPSJHcmVlbnMiKVstMV0KdGNvbHMgPC0gYnJld2VyLnBhbChuPTgsIG5hbWU9IlJlZHMiKVstMV0Kbmtjb2xzIDwtIGMoIiM4NzYxNDkiLCIjNmUzZjIyIikKYmNvbHMgPC0gYnJld2VyLnBhbChuPTQsIG5hbWU9IlB1cnBsZXMiKVstMV0Kb3RoY29scyA8LSBjKCIjNzFhMTU3IiwiIzAwYzVjYyIsIiNhMThlMjUiLCIjYjI4MmIzIikKc3RyY29scyA8LSBicmV3ZXIucGFsKG49NCwgbmFtZT0iT3JhbmdlcyIpWy0xXQp3Y2NvbHMgPSBjKCIjODc4Nzg3IiwgIiM1MThkYjYiLCIjOTRjYzczIiwiI2U5NmI1MyIpCgpjb2xzIDwtIGMobWFjY29scyxtb25vY29scyxkY2NvbHMsdGNvbHMsbmtjb2xzLGJjb2xzLG90aGNvbHMsc3RyY29scykKCmxsY29scyA8LSBjKCIjNDI5MkM2IiwiI2ZmOGFkZSIsIiMyMzhCNDUiLCIjRUYzQjJDIiwiIzg3NjE0OSIsIiM5RTlBQzgiLCIjNzFhMTU3IiwiIzAwYzVjYyIsIiNhMThlMjUiLCIjYjI4MmIzIiwiI0ZEOEQzQyIpCmBgYAoKIyMgUGxvdCBDZWxsIFR5cGVzCgpgYGB7ciBjZWxsdHlwZXMsIGZpZy53aWR0aD02LCBmaWcuaGVpZ2h0PTZ9CkRpbVBsb3QoZGF0YS5pbnRlZ3JhdGVkLCBncm91cC5ieT0ibG93bGV2ZWwyIiwgY29scz1sbGNvbHMsIGxhYmVsPVQpICsgCiAgTm9MZWdlbmQoKSArIAogIGxhYnModGl0bGU9IkNlbGwgVHlwZXMiKQpgYGAKCiMjIFBsb3QgU3ViY2x1c3RlcnMKCmBgYHtyIHN1YmNsdXN0ZXJzLCBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD04fQpEaW1QbG90KGRhdGEuaW50ZWdyYXRlZCwgZ3JvdXAuYnk9ImhpZ2hsZXZlbDIiLCBjb2xzPWNvbHMpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJib3R0b20iLCBsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZT03KSkgKyAKICBsYWJzKHRpdGxlPSJTdWJjbHVzdGVycyIpCmBgYAoKIyBTYXZlIFByb2dyZXNzCgpgYGB7ciBzYXZlUkRTfQpzYXZlUkRTKGRhdGEuaW50ZWdyYXRlZCwgZmlsZT0iSW50ZWdyYXRlZERhdGEuUkRTIikKYGBgCgoKIyBTZXNzaW9uIEluZm8KCmBgYHtyIHNlc3Npb25pbmZvfQpzZXNzaW9uSW5mbygpCmBgYAoK